170 lines
4.8 KiB
C#
170 lines
4.8 KiB
C#
using System;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using Febucci.UI.Core;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using AibisDream.Framework;
|
||
using AibisDream.Utility;
|
||
|
||
namespace AibisDream
|
||
{
|
||
public class OnelineBox : MonoBehaviour, ILineView
|
||
{
|
||
[SerializeField] private TypewriterCore content;
|
||
[SerializeField] private GameObject box;
|
||
|
||
[Header("排版参数")]
|
||
[SerializeField] private int maxWidth = 800;
|
||
[SerializeField] private int minWidth = 10;
|
||
|
||
private LayoutElement _contentLayoutElement;
|
||
private TMP_Text _contentText;
|
||
private RectTransform _rectTransform;
|
||
private CancellationTokenSource _autoHideToken;
|
||
private event Action OnTextShowed;
|
||
private bool _isInitialized;
|
||
|
||
// ---------------------------- 显示逻辑 ----------------------------
|
||
|
||
public void RunLine(LineSyncToken syncToken)
|
||
{
|
||
// 先中断结束事件
|
||
_autoHideToken?.Cancel();
|
||
_autoHideToken = null;
|
||
|
||
// 注册事件
|
||
OnTextShowed += syncToken.TextShown;
|
||
syncToken.SkipTextAnima += () => content.SkipTypewriter();
|
||
syncToken.OnAdvance += AfterAdvance;
|
||
|
||
// TMP ClearMesh 依赖 canvasRenderer;box 未激活时 SetText 会 NRE
|
||
if (box != null && !box.activeSelf)
|
||
box.SetActive(true);
|
||
|
||
// 播放文字
|
||
content.TextAnimator.SetText(string.Empty);
|
||
var lineText = GetOneLineText(syncToken.lineInfo);
|
||
HandleLayout(lineText);
|
||
content.ShowText(lineText);
|
||
syncToken.TextStart();
|
||
}
|
||
|
||
private string GetOneLineText(LineInfo lineInfo)
|
||
{
|
||
if (string.IsNullOrEmpty(lineInfo.character.GetActorName()))
|
||
{
|
||
return lineInfo.lineText;
|
||
}
|
||
|
||
return $"<notype>{lineInfo.character.GetActorName()}: </notype>{lineInfo.lineText}";
|
||
}
|
||
|
||
private void HandleLayout(string line)
|
||
{
|
||
if (!_isInitialized)
|
||
{
|
||
InitRefs();
|
||
}
|
||
|
||
// 去除富文本标签后计算宽度
|
||
var width = DialogUIManager.Instance.EstimateTextWidth(line.RemoveRichTextTags(), _contentText.fontSize);
|
||
|
||
if (width > maxWidth)
|
||
{
|
||
_contentLayoutElement.preferredWidth = maxWidth;
|
||
}
|
||
else
|
||
{
|
||
_contentLayoutElement.preferredWidth = -1; // 自适应
|
||
}
|
||
|
||
_contentLayoutElement.minWidth = minWidth;
|
||
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(_rectTransform);
|
||
}
|
||
|
||
private async void AfterAdvance()
|
||
{
|
||
_autoHideToken = new CancellationTokenSource();
|
||
try
|
||
{
|
||
await Task.Delay(ConstRef.AutoHideDelay, _autoHideToken.Token);
|
||
HideDialog();
|
||
}
|
||
catch (TaskCanceledException)
|
||
{
|
||
// 忽略取消
|
||
}
|
||
}
|
||
|
||
public void HideDialog()
|
||
{
|
||
box.SetActive(false);
|
||
}
|
||
|
||
// ---------------------------- 生命周期 ----------------------------
|
||
|
||
private void Awake()
|
||
{
|
||
box.SetActive(false);
|
||
InitRefs();
|
||
}
|
||
|
||
private void InitRefs()
|
||
{
|
||
if (_isInitialized) return;
|
||
|
||
_rectTransform = box.GetComponent<RectTransform>();
|
||
_contentText = content.GetComponent<TMP_Text>();
|
||
_contentLayoutElement = content.GetComponent<LayoutElement>();
|
||
_isInitialized = true;
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
DialogUIManager.Instance.RegisterScreenView(DialogViewType.OnelineBox, this);
|
||
RegisterEvents();
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.OnelineBox);
|
||
UnregisterEvents();
|
||
OnTextShowed = null;
|
||
}
|
||
|
||
private void RegisterEvents()
|
||
{
|
||
// 全局事件
|
||
EnumEventSystem.Global.Register(DialogEventEnum.OptionShow, OnOptionShow);
|
||
|
||
// 文本事件
|
||
content.onTextShowed.AddListener(TextShowed);
|
||
}
|
||
|
||
private void UnregisterEvents()
|
||
{
|
||
// 全局事件
|
||
EnumEventSystem.Global.UnRegister(DialogEventEnum.OptionShow, OnOptionShow);
|
||
|
||
// 文本事件
|
||
content.onTextShowed.RemoveListener(TextShowed);
|
||
}
|
||
|
||
private void TextShowed()
|
||
{
|
||
OnTextShowed?.Invoke();
|
||
OnTextShowed = null;
|
||
}
|
||
|
||
private void OnOptionShow()
|
||
{
|
||
_autoHideToken?.Cancel();
|
||
_autoHideToken = null;
|
||
|
||
HideDialog();
|
||
}
|
||
}
|
||
} |