refactor(ui): 重构文字宽度计算和对话框布局逻辑

This commit is contained in:
2026-03-13 21:04:13 +08:00
parent 67ca0234df
commit e639d83c2d
7 changed files with 78 additions and 28 deletions
+1 -1
View File
@@ -162,7 +162,7 @@ namespace AibisDream
}
// 先去除富文本标签
var width = _bubbleGroup.EstimateTextWidth(line.RemoveRichTextTags(), _lineText.fontSize);
var width = DialogUIManager.Instance.EstimateTextWidth(line.RemoveRichTextTags(), _lineText.fontSize);
if (width > maxWidth)
{
_layoutElement.preferredWidth = maxWidth;
@@ -6,15 +6,12 @@ using System.Threading.Tasks;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
namespace AibisDream
{
public class BubbleGroup : MonoBehaviour, ILineView
{
[SerializeField] private TMP_Text widthEstimation;
private Dictionary<ActorRole, Bubble[]> _bubbleDict = new();
private BubbleFactory _bubbleFactory;
private CancellationTokenSource _autoHideToken;
@@ -89,14 +86,6 @@ namespace AibisDream
}
}
public float EstimateTextWidth(string text, float fontSize)
{
widthEstimation.fontSize = fontSize;
widthEstimation.text = text;
widthEstimation.ForceMeshUpdate();
return widthEstimation.preferredWidth;
}
private async void AfterAdvance()
{
_autoHideToken = new CancellationTokenSource();
@@ -1,6 +1,7 @@
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.UI;
using TMPro;
using UnityEngine;
namespace AibisDream
@@ -9,6 +10,7 @@ namespace AibisDream
{
[SerializeField] private LineRunner lineView;
[SerializeField] private OptionView optionView;
[SerializeField] private TMP_Text widthEstimation;
public override void OnSingletonInit()
{
@@ -77,6 +79,14 @@ namespace AibisDream
lineView.LoadBubbleData(data);
optionView.LoadBubbles(data);
}
public float EstimateTextWidth(string text, float fontSize)
{
widthEstimation.fontSize = fontSize;
widthEstimation.text = text;
widthEstimation.ForceMeshUpdate();
return widthEstimation.preferredWidth;
}
}
public enum DialogViewType
+50 -6
View File
@@ -1,8 +1,10 @@
using System;
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;
@@ -13,14 +15,21 @@ namespace AibisDream
[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)
{
Debug.Log("OnelineBox: " + syncToken.lineInfo.lineText);
// 先中断结束事件
_autoHideToken?.Cancel();
_autoHideToken = null;
@@ -32,11 +41,11 @@ namespace AibisDream
// 播放文字
content.TextAnimator.SetText(string.Empty);
Debug.Log("OnelineBox: " + GetOneLineText(syncToken.lineInfo));
var lineText = GetOneLineText(syncToken.lineInfo);
box.SetActive(true);
content.ShowText(GetOneLineText(syncToken.lineInfo));
HandleLayout(lineText);
content.ShowText(lineText);
syncToken.TextStart();
Debug.Log("OnelineBox: TextStart");
}
private string GetOneLineText(LineInfo lineInfo)
@@ -45,10 +54,34 @@ namespace AibisDream
{
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();
@@ -73,6 +106,17 @@ namespace AibisDream
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()
@@ -1,7 +1,8 @@
using System;
using System;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using AibisDream.Utility;
namespace AibisDream
{
@@ -49,23 +50,23 @@ namespace AibisDream
switch (state)
{
case SelectionType.Normal:
arrow.gameObject.SetActive(false);
arrow.SetAlpha(0f);
SetColor(colorBlock.normalColor);
break;
case SelectionType.Highlighted:
arrow.gameObject.SetActive(true);
arrow.SetAlpha(1f);
SetColor(colorBlock.highlightedColor);
break;
case SelectionType.Pressed:
arrow.gameObject.SetActive(true);
arrow.SetAlpha(1f);
SetColor(colorBlock.pressedColor);
break;
case SelectionType.Selected:
arrow.gameObject.SetActive(true);
arrow.SetAlpha(1f);
SetColor(colorBlock.selectedColor);
break;
case SelectionType.Disabled:
arrow.gameObject.SetActive(false);
arrow.SetAlpha(0f);
SetColor(colorBlock.disabledColor);
break;
}
@@ -1,4 +1,4 @@
using UnityEngine;
using UnityEngine;
using AibisDream.Framework;
namespace AibisDream
@@ -12,8 +12,6 @@ namespace AibisDream
{
gameObject.SetActive(true);
Debug.Log($"ShowOptions: {dialogOptions.Length}, {dialogOptions[0].Line}");
// 生成新按钮
foreach (var option in dialogOptions)
{
+9 -1
View File
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
@@ -10,6 +10,7 @@ using UnityEngine;
using Object = UnityEngine.Object;
using System.Globalization;
using UnityEditor;
using UnityEngine.UI;
namespace AibisDream.Utility
{
@@ -185,6 +186,13 @@ namespace AibisDream.Utility
renderer.color = color;
}
public static void SetAlpha(this Image image, float targetAlpha)
{
Color color = image.color;
color.a = targetAlpha;
image.color = color;
}
public static void DestroyAllChildren(this Transform self)
{
if (self == null)