997 lines
31 KiB
C#
997 lines
31 KiB
C#
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
/// <summary>
|
||
/// TMP InputField 自动设置脚本
|
||
/// 解决文本截断显示"..."的问题,自动配置正确的显示属性
|
||
/// 可以直接挂在包含TMP_InputField的GameObject上使用
|
||
/// </summary>
|
||
public class TMPInputFieldAutoSetup : MonoBehaviour
|
||
{
|
||
[Header("自动设置选项")]
|
||
[Tooltip("文本溢出模式:0=Overflow(截断), 1=Page(分页), 2=Linked(链接)")]
|
||
[SerializeField] private TextOverflowModes overflowMode = TextOverflowModes.Page;
|
||
|
||
[Tooltip("是否启用自动换行")]
|
||
[SerializeField] private bool enableWordWrapping = true;
|
||
|
||
[Tooltip("是否启用自动调整字体大小")]
|
||
[SerializeField] private bool enableAutoSizing = false;
|
||
|
||
[Tooltip("最小字体大小")]
|
||
[SerializeField] private float fontSizeMin = 12f;
|
||
|
||
[Tooltip("最大字体大小")]
|
||
[SerializeField] private float fontSizeMax = 72f;
|
||
|
||
[Tooltip("是否在Awake时自动应用设置")]
|
||
[SerializeField] private bool autoApplyOnAwake = true;
|
||
|
||
[Tooltip("是否启用调试日志")]
|
||
[SerializeField] private bool enableDebugLog = true;
|
||
|
||
[Tooltip("是否启用自适应滚动条")]
|
||
[SerializeField] private bool enableAdaptiveScrollbar = true;
|
||
|
||
[Tooltip("滚动条显示/隐藏动画时间")]
|
||
[SerializeField] private float scrollbarAnimationTime = 0.3f;
|
||
|
||
[Header("组件引用")]
|
||
[Tooltip("TMP InputField组件")]
|
||
[SerializeField] private TMP_InputField inputField;
|
||
|
||
[Tooltip("TMP Text组件(内部文本显示组件)")]
|
||
[SerializeField] private TMP_Text textComponent;
|
||
|
||
[Tooltip("ScrollRect组件(可选,用于滚动显示)")]
|
||
[SerializeField] private ScrollRect scrollRect;
|
||
|
||
[Tooltip("Content Size Fitter组件(可选,用于自动调整Content大小)")]
|
||
[SerializeField] private ContentSizeFitter contentSizeFitter;
|
||
|
||
[Tooltip("Layout Group组件(可选,可能限制文本显示)")]
|
||
[SerializeField] private LayoutGroup layoutGroup;
|
||
|
||
[Tooltip("垂直滚动条(可选,用于自适应显示)")]
|
||
[SerializeField] private Scrollbar verticalScrollbar;
|
||
|
||
[Tooltip("水平滚动条(可选,用于自适应显示)")]
|
||
[SerializeField] private Scrollbar horizontalScrollbar;
|
||
|
||
/// <summary>
|
||
/// 文本溢出模式枚举
|
||
/// </summary>
|
||
public enum TextOverflowModes
|
||
{
|
||
Overflow = 0, // 溢出模式(会截断文本)
|
||
Page = 1, // 分页模式(推荐用于长文本)
|
||
Linked = 2 // 链接模式(用于链接文本)
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化组件
|
||
/// </summary>
|
||
private void Awake()
|
||
{
|
||
// 自动检测组件
|
||
AutoDetectComponents();
|
||
|
||
// 如果启用自动应用,则应用设置
|
||
if (autoApplyOnAwake)
|
||
{
|
||
ApplySettings();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动检测TMP_InputField和TMP_Text组件
|
||
/// </summary>
|
||
private void AutoDetectComponents()
|
||
{
|
||
// 检测TMP_InputField组件
|
||
if (inputField == null)
|
||
{
|
||
inputField = GetComponent<TMP_InputField>();
|
||
}
|
||
|
||
if (inputField == null)
|
||
{
|
||
Debug.LogError($"TMPInputFieldAutoSetup: 在 {gameObject.name} 中未找到TMP_InputField组件!");
|
||
return;
|
||
}
|
||
|
||
// 检测TMP_Text组件(InputField内部的文本显示组件)
|
||
if (textComponent == null)
|
||
{
|
||
textComponent = inputField.textComponent;
|
||
}
|
||
|
||
if (textComponent == null)
|
||
{
|
||
Debug.LogError($"TMPInputFieldAutoSetup: 在TMP_InputField中未找到TMP_Text组件!");
|
||
return;
|
||
}
|
||
|
||
// 检测ScrollRect组件(在父级或同级中查找)
|
||
if (scrollRect == null)
|
||
{
|
||
scrollRect = GetComponentInParent<ScrollRect>();
|
||
if (scrollRect == null)
|
||
{
|
||
scrollRect = GetComponent<ScrollRect>();
|
||
}
|
||
}
|
||
|
||
// 检测Content Size Fitter组件
|
||
if (contentSizeFitter == null && scrollRect != null)
|
||
{
|
||
contentSizeFitter = scrollRect.content.GetComponent<ContentSizeFitter>();
|
||
}
|
||
|
||
// 检测Layout Group组件
|
||
if (layoutGroup == null)
|
||
{
|
||
layoutGroup = GetComponentInParent<LayoutGroup>();
|
||
}
|
||
|
||
// 检测滚动条组件
|
||
if (verticalScrollbar == null && scrollRect != null)
|
||
{
|
||
verticalScrollbar = scrollRect.verticalScrollbar;
|
||
}
|
||
if (horizontalScrollbar == null && scrollRect != null)
|
||
{
|
||
horizontalScrollbar = scrollRect.horizontalScrollbar;
|
||
}
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: 组件检测完成 - {gameObject.name}\n" +
|
||
$"InputField: {(inputField != null ? "已找到" : "未找到")}\n" +
|
||
$"TextComponent: {(textComponent != null ? "已找到" : "未找到")}\n" +
|
||
$"ScrollRect: {(scrollRect != null ? "已找到" : "未找到")}\n" +
|
||
$"ContentSizeFitter: {(contentSizeFitter != null ? "已找到" : "未找到")}\n" +
|
||
$"LayoutGroup: {(layoutGroup != null ? "已找到" : "未找到")}\n" +
|
||
$"垂直滚动条: {(verticalScrollbar != null ? "已找到" : "未找到")}\n" +
|
||
$"水平滚动条: {(horizontalScrollbar != null ? "已找到" : "未找到")}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用文本显示设置
|
||
/// </summary>
|
||
public void ApplySettings()
|
||
{
|
||
if (textComponent == null)
|
||
{
|
||
Debug.LogWarning("TMPInputFieldAutoSetup: TMP_Text组件为空,无法应用设置");
|
||
return;
|
||
}
|
||
|
||
// 设置文本溢出模式
|
||
textComponent.overflowMode = (TMPro.TextOverflowModes)overflowMode;
|
||
|
||
// 设置自动换行
|
||
textComponent.enableWordWrapping = enableWordWrapping;
|
||
|
||
// 设置自动调整字体大小
|
||
textComponent.enableAutoSizing = enableAutoSizing;
|
||
|
||
if (enableAutoSizing)
|
||
{
|
||
textComponent.fontSizeMin = fontSizeMin;
|
||
textComponent.fontSizeMax = fontSizeMax;
|
||
}
|
||
|
||
// 设置InputField为多行模式(如果文本很长)
|
||
if (inputField != null)
|
||
{
|
||
inputField.lineType = TMP_InputField.LineType.MultiLineNewline;
|
||
}
|
||
|
||
// 配置ScrollRect Content
|
||
SetupScrollRectContent();
|
||
|
||
// 设置文本组件的RectTransform
|
||
SetupTextRectTransform();
|
||
|
||
// 移除布局限制
|
||
RemoveLayoutConstraints();
|
||
|
||
// 强制刷新布局
|
||
ForceRefreshLayout();
|
||
|
||
// 更新自适应滚动条
|
||
if (enableAdaptiveScrollbar)
|
||
{
|
||
StartCoroutine(DelayedScrollbarUpdate());
|
||
}
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: 设置已应用 - 溢出模式: {overflowMode}, 换行: {enableWordWrapping}, 自动调整: {enableAutoSizing}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置ScrollRect Content属性
|
||
/// </summary>
|
||
private void SetupScrollRectContent()
|
||
{
|
||
if (scrollRect == null || scrollRect.content == null)
|
||
{
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log("TMPInputFieldAutoSetup: 未找到ScrollRect或Content,跳过Content设置");
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 确保ScrollRect滚动功能正常
|
||
scrollRect.horizontal = true;
|
||
scrollRect.vertical = true;
|
||
scrollRect.movementType = ScrollRect.MovementType.Clamped;
|
||
scrollRect.inertia = true;
|
||
scrollRect.decelerationRate = 0.135f;
|
||
scrollRect.scrollSensitivity = 20f;
|
||
|
||
// 确保Content Size Fitter存在
|
||
if (contentSizeFitter == null)
|
||
{
|
||
contentSizeFitter = scrollRect.content.GetComponent<ContentSizeFitter>();
|
||
if (contentSizeFitter == null)
|
||
{
|
||
contentSizeFitter = scrollRect.content.gameObject.AddComponent<ContentSizeFitter>();
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log("TMPInputFieldAutoSetup: 已添加ContentSizeFitter组件");
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设置Content Size Fitter属性(保持滚动功能)
|
||
if (contentSizeFitter != null)
|
||
{
|
||
contentSizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||
contentSizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||
}
|
||
|
||
// 确保Content的RectTransform设置正确(保持滚动功能)
|
||
RectTransform contentRect = scrollRect.content;
|
||
if (contentRect != null)
|
||
{
|
||
// 设置Content的锚点(保持滚动功能)
|
||
contentRect.anchorMin = new Vector2(0, 0);
|
||
contentRect.anchorMax = new Vector2(1, 1);
|
||
contentRect.pivot = new Vector2(0.5f, 0.5f);
|
||
|
||
// 确保Content有足够的最小高度
|
||
if (contentRect.sizeDelta.y < 100f)
|
||
{
|
||
contentRect.sizeDelta = new Vector2(contentRect.sizeDelta.x, 100f);
|
||
}
|
||
}
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: ScrollRect Content设置完成 - Content高度: {contentRect.sizeDelta.y}, 滚动功能已启用");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置文本溢出模式
|
||
/// </summary>
|
||
/// <param name="mode">溢出模式</param>
|
||
public void SetOverflowMode(TextOverflowModes mode)
|
||
{
|
||
overflowMode = mode;
|
||
if (textComponent != null)
|
||
{
|
||
textComponent.overflowMode = (TMPro.TextOverflowModes)mode;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置是否启用自动换行
|
||
/// </summary>
|
||
/// <param name="enable">是否启用</param>
|
||
public void SetWordWrapping(bool enable)
|
||
{
|
||
enableWordWrapping = enable;
|
||
if (textComponent != null)
|
||
{
|
||
textComponent.enableWordWrapping = enable;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置是否启用自动调整字体大小
|
||
/// </summary>
|
||
/// <param name="enable">是否启用</param>
|
||
public void SetAutoSizing(bool enable)
|
||
{
|
||
enableAutoSizing = enable;
|
||
if (textComponent != null)
|
||
{
|
||
textComponent.enableAutoSizing = enable;
|
||
if (enable)
|
||
{
|
||
textComponent.fontSizeMin = fontSizeMin;
|
||
textComponent.fontSizeMax = fontSizeMax;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置字体大小范围
|
||
/// </summary>
|
||
/// <param name="min">最小字体大小</param>
|
||
/// <param name="max">最大字体大小</param>
|
||
public void SetFontSizeRange(float min, float max)
|
||
{
|
||
fontSizeMin = min;
|
||
fontSizeMax = max;
|
||
|
||
if (textComponent != null && enableAutoSizing)
|
||
{
|
||
textComponent.fontSizeMin = min;
|
||
textComponent.fontSizeMax = max;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前文本内容长度
|
||
/// </summary>
|
||
/// <returns>文本长度</returns>
|
||
public int GetTextLength()
|
||
{
|
||
return inputField?.text?.Length ?? 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前文本内容
|
||
/// </summary>
|
||
/// <returns>文本内容</returns>
|
||
public string GetText()
|
||
{
|
||
return inputField?.text ?? string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置测试文本(用于验证设置效果)
|
||
/// </summary>
|
||
/// <param name="testText">测试文本</param>
|
||
public void SetTestText(string testText)
|
||
{
|
||
if (inputField != null)
|
||
{
|
||
inputField.text = testText;
|
||
|
||
// 延迟调整Content高度,确保文本已经渲染
|
||
StartCoroutine(AdjustContentHeightAfterTextUpdate());
|
||
|
||
// 延迟更新滚动条
|
||
if (enableAdaptiveScrollbar)
|
||
{
|
||
StartCoroutine(DelayedScrollbarUpdate());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延迟调整Content高度
|
||
/// </summary>
|
||
private System.Collections.IEnumerator AdjustContentHeightAfterTextUpdate()
|
||
{
|
||
// 等待一帧,确保文本已经渲染
|
||
yield return null;
|
||
|
||
// 调整Content高度
|
||
AdjustContentHeight();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 调整Content高度以适应文本内容
|
||
/// </summary>
|
||
public void AdjustContentHeight()
|
||
{
|
||
if (scrollRect == null || scrollRect.content == null || textComponent == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 强制文本组件重新计算布局
|
||
textComponent.SetVerticesDirty();
|
||
textComponent.SetAllDirty();
|
||
|
||
// 等待布局更新
|
||
Canvas.ForceUpdateCanvases();
|
||
|
||
// 获取文本的首选高度
|
||
float preferredHeight = textComponent.preferredHeight;
|
||
|
||
// 设置Content的最小高度
|
||
RectTransform contentRect = scrollRect.content;
|
||
if (contentRect != null && preferredHeight > 0)
|
||
{
|
||
// 确保Content高度至少等于文本的首选高度
|
||
if (contentRect.sizeDelta.y < preferredHeight)
|
||
{
|
||
contentRect.sizeDelta = new Vector2(contentRect.sizeDelta.x, preferredHeight + 20f); // 额外20像素边距
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: Content高度已调整 - 文本高度: {preferredHeight}, Content高度: {contentRect.sizeDelta.y}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 强制显示完整文本(终极解决方案)
|
||
/// </summary>
|
||
public void ForceShowFullText()
|
||
{
|
||
if (textComponent == null)
|
||
{
|
||
Debug.LogWarning("TMPInputFieldAutoSetup: TMP_Text组件为空,无法强制显示完整文本");
|
||
return;
|
||
}
|
||
|
||
// 1. 设置文本溢出模式为Page
|
||
textComponent.overflowMode = TMPro.TextOverflowModes.Page;
|
||
|
||
// 2. 启用自动换行
|
||
textComponent.enableWordWrapping = true;
|
||
|
||
// 3. 设置文本组件的RectTransform
|
||
SetupTextRectTransform();
|
||
|
||
// 4. 移除布局限制
|
||
RemoveLayoutConstraints();
|
||
|
||
// 5. 强制刷新布局
|
||
ForceRefreshLayout();
|
||
|
||
// 6. 调整所有相关组件的大小
|
||
AdjustAllSizes();
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log("TMPInputFieldAutoSetup: 已强制显示完整文本");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置文本组件的RectTransform
|
||
/// </summary>
|
||
private void SetupTextRectTransform()
|
||
{
|
||
if (textComponent == null) return;
|
||
|
||
RectTransform textRect = textComponent.rectTransform;
|
||
|
||
// 设置文本组件的锚点和轴心点
|
||
textRect.anchorMin = Vector2.zero;
|
||
textRect.anchorMax = Vector2.one;
|
||
textRect.pivot = new Vector2(0.5f, 0.5f);
|
||
|
||
// 设置文本组件的偏移为0,让它填满父容器
|
||
textRect.offsetMin = Vector2.zero;
|
||
textRect.offsetMax = Vector2.zero;
|
||
|
||
// 确保文本组件有足够的大小
|
||
if (textRect.sizeDelta.x < 100f)
|
||
{
|
||
textRect.sizeDelta = new Vector2(100f, textRect.sizeDelta.y);
|
||
}
|
||
if (textRect.sizeDelta.y < 50f)
|
||
{
|
||
textRect.sizeDelta = new Vector2(textRect.sizeDelta.x, 50f);
|
||
}
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: 文本RectTransform已设置 - 大小: {textRect.sizeDelta}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除布局限制
|
||
/// </summary>
|
||
private void RemoveLayoutConstraints()
|
||
{
|
||
// 检测并处理Layout Group
|
||
if (layoutGroup == null)
|
||
{
|
||
layoutGroup = GetComponentInParent<LayoutGroup>();
|
||
}
|
||
|
||
if (layoutGroup != null)
|
||
{
|
||
// 临时禁用Layout Group
|
||
layoutGroup.enabled = false;
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: 已临时禁用Layout Group: {layoutGroup.GetType().Name}");
|
||
}
|
||
}
|
||
|
||
// 检测并处理Content Size Fitter的限制
|
||
if (contentSizeFitter != null)
|
||
{
|
||
// 确保Content Size Fitter设置为PreferredSize
|
||
contentSizeFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||
contentSizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 强制刷新布局
|
||
/// </summary>
|
||
private void ForceRefreshLayout()
|
||
{
|
||
// 强制所有Canvas更新
|
||
Canvas.ForceUpdateCanvases();
|
||
|
||
// 强制文本组件重新计算布局
|
||
if (textComponent != null)
|
||
{
|
||
textComponent.SetVerticesDirty();
|
||
textComponent.SetAllDirty();
|
||
textComponent.ForceMeshUpdate();
|
||
}
|
||
|
||
// 强制InputField重新计算布局(通过修改其RectTransform)
|
||
if (inputField != null)
|
||
{
|
||
RectTransform inputRect = inputField.GetComponent<RectTransform>();
|
||
if (inputRect != null)
|
||
{
|
||
// 通过临时修改大小来触发重新计算
|
||
Vector2 currentSize = inputRect.sizeDelta;
|
||
inputRect.sizeDelta = new Vector2(currentSize.x, currentSize.y + 0.1f);
|
||
inputRect.sizeDelta = currentSize;
|
||
}
|
||
}
|
||
|
||
// 强制ScrollRect Content重新计算布局
|
||
if (scrollRect != null && scrollRect.content != null)
|
||
{
|
||
// 通过修改Content的大小来触发重新计算
|
||
Vector2 currentSize = scrollRect.content.sizeDelta;
|
||
scrollRect.content.sizeDelta = new Vector2(currentSize.x, currentSize.y + 0.1f);
|
||
scrollRect.content.sizeDelta = currentSize;
|
||
}
|
||
|
||
// 等待一帧后再次更新
|
||
StartCoroutine(DelayedLayoutRefresh());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延迟布局刷新
|
||
/// </summary>
|
||
private System.Collections.IEnumerator DelayedLayoutRefresh()
|
||
{
|
||
yield return null;
|
||
Canvas.ForceUpdateCanvases();
|
||
|
||
if (textComponent != null)
|
||
{
|
||
textComponent.SetVerticesDirty();
|
||
textComponent.ForceMeshUpdate();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延迟更新滚动条
|
||
/// </summary>
|
||
private System.Collections.IEnumerator DelayedScrollbarUpdate()
|
||
{
|
||
// 等待布局更新完成
|
||
yield return new WaitForEndOfFrame();
|
||
yield return null;
|
||
|
||
// 更新滚动条
|
||
UpdateAdaptiveScrollbar();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 调整所有相关组件的大小
|
||
/// </summary>
|
||
private void AdjustAllSizes()
|
||
{
|
||
// 调整InputField的大小
|
||
if (inputField != null)
|
||
{
|
||
RectTransform inputRect = inputField.GetComponent<RectTransform>();
|
||
if (inputRect != null && inputRect.sizeDelta.y < 100f)
|
||
{
|
||
inputRect.sizeDelta = new Vector2(inputRect.sizeDelta.x, 100f);
|
||
}
|
||
}
|
||
|
||
// 调整ScrollRect Content的大小
|
||
AdjustContentHeight();
|
||
|
||
// 调整ScrollRect Viewport的大小
|
||
if (scrollRect != null && scrollRect.viewport != null)
|
||
{
|
||
RectTransform viewportRect = scrollRect.viewport;
|
||
if (viewportRect.sizeDelta.y < 100f)
|
||
{
|
||
viewportRect.sizeDelta = new Vector2(viewportRect.sizeDelta.x, 100f);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 恢复ScrollRect滚动功能
|
||
/// </summary>
|
||
public void RestoreScrollRectFunctionality()
|
||
{
|
||
if (scrollRect == null)
|
||
{
|
||
Debug.LogWarning("TMPInputFieldAutoSetup: ScrollRect为空,无法恢复滚动功能");
|
||
return;
|
||
}
|
||
|
||
// 恢复ScrollRect的基本滚动设置
|
||
scrollRect.horizontal = true;
|
||
scrollRect.vertical = true;
|
||
scrollRect.movementType = ScrollRect.MovementType.Clamped;
|
||
scrollRect.inertia = true;
|
||
scrollRect.decelerationRate = 0.135f;
|
||
scrollRect.scrollSensitivity = 20f;
|
||
|
||
// 确保ScrollRect的Content设置正确
|
||
if (scrollRect.content != null)
|
||
{
|
||
RectTransform contentRect = scrollRect.content;
|
||
contentRect.anchorMin = new Vector2(0, 0);
|
||
contentRect.anchorMax = new Vector2(1, 1);
|
||
contentRect.pivot = new Vector2(0.5f, 0.5f);
|
||
}
|
||
|
||
// 重新启用Layout Group(如果之前被禁用)
|
||
if (layoutGroup != null && !layoutGroup.enabled)
|
||
{
|
||
layoutGroup.enabled = true;
|
||
}
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log("TMPInputFieldAutoSetup: ScrollRect滚动功能已恢复");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查ScrollRect滚动状态
|
||
/// </summary>
|
||
/// <returns>滚动功能是否正常</returns>
|
||
public bool CheckScrollRectStatus()
|
||
{
|
||
if (scrollRect == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool isScrollable = scrollRect.horizontal || scrollRect.vertical;
|
||
bool hasContent = scrollRect.content != null;
|
||
bool contentHasSize = hasContent && scrollRect.content.sizeDelta.y > 0;
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: ScrollRect状态检查\n" +
|
||
$"可滚动: {isScrollable}\n" +
|
||
$"有Content: {hasContent}\n" +
|
||
$"Content有大小: {contentHasSize}\n" +
|
||
$"水平滚动: {scrollRect.horizontal}\n" +
|
||
$"垂直滚动: {scrollRect.vertical}");
|
||
}
|
||
|
||
return isScrollable && hasContent && contentHasSize;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自适应滚动条显示/隐藏
|
||
/// </summary>
|
||
public void UpdateAdaptiveScrollbar()
|
||
{
|
||
if (!enableAdaptiveScrollbar || scrollRect == null || textComponent == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 获取文本内容的高度
|
||
float textHeight = textComponent.preferredHeight;
|
||
|
||
// 获取ScrollRect Viewport的高度
|
||
float viewportHeight = scrollRect.viewport.rect.height;
|
||
|
||
// 获取ScrollRect Content的高度
|
||
float contentHeight = scrollRect.content.rect.height;
|
||
|
||
// 判断是否需要垂直滚动条
|
||
bool needsVerticalScrollbar = contentHeight > viewportHeight;
|
||
|
||
// 判断是否需要水平滚动条(通常文本会自动换行,所以水平滚动条很少需要)
|
||
bool needsHorizontalScrollbar = false; // 可以根据需要调整
|
||
|
||
// 更新垂直滚动条
|
||
if (verticalScrollbar != null)
|
||
{
|
||
UpdateScrollbarVisibility(verticalScrollbar, needsVerticalScrollbar);
|
||
}
|
||
|
||
// 更新水平滚动条
|
||
if (horizontalScrollbar != null)
|
||
{
|
||
UpdateScrollbarVisibility(horizontalScrollbar, needsHorizontalScrollbar);
|
||
}
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: 自适应滚动条更新\n" +
|
||
$"文本高度: {textHeight}\n" +
|
||
$"Viewport高度: {viewportHeight}\n" +
|
||
$"Content高度: {contentHeight}\n" +
|
||
$"需要垂直滚动条: {needsVerticalScrollbar}\n" +
|
||
$"需要水平滚动条: {needsHorizontalScrollbar}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新滚动条的显示/隐藏状态
|
||
/// </summary>
|
||
/// <param name="scrollbar">滚动条组件</param>
|
||
/// <param name="shouldShow">是否应该显示</param>
|
||
private void UpdateScrollbarVisibility(Scrollbar scrollbar, bool shouldShow)
|
||
{
|
||
if (scrollbar == null) return;
|
||
|
||
// 停止之前的动画
|
||
StopCoroutine(AnimateScrollbarVisibility(scrollbar, shouldShow));
|
||
|
||
// 开始新的动画
|
||
StartCoroutine(AnimateScrollbarVisibility(scrollbar, shouldShow));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 滚动条显示/隐藏动画
|
||
/// </summary>
|
||
/// <param name="scrollbar">滚动条组件</param>
|
||
/// <param name="shouldShow">是否应该显示</param>
|
||
private System.Collections.IEnumerator AnimateScrollbarVisibility(Scrollbar scrollbar, bool shouldShow)
|
||
{
|
||
CanvasGroup canvasGroup = scrollbar.GetComponent<CanvasGroup>();
|
||
if (canvasGroup == null)
|
||
{
|
||
canvasGroup = scrollbar.gameObject.AddComponent<CanvasGroup>();
|
||
}
|
||
|
||
float startAlpha = canvasGroup.alpha;
|
||
float targetAlpha = shouldShow ? 1f : 0f;
|
||
float elapsedTime = 0f;
|
||
|
||
while (elapsedTime < scrollbarAnimationTime)
|
||
{
|
||
elapsedTime += Time.deltaTime;
|
||
float progress = elapsedTime / scrollbarAnimationTime;
|
||
|
||
// 使用平滑插值
|
||
canvasGroup.alpha = Mathf.Lerp(startAlpha, targetAlpha, progress);
|
||
|
||
yield return null;
|
||
}
|
||
|
||
// 确保最终状态正确
|
||
canvasGroup.alpha = targetAlpha;
|
||
|
||
// 如果完全隐藏,禁用交互
|
||
scrollbar.interactable = shouldShow;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置自适应滚动条功能
|
||
/// </summary>
|
||
/// <param name="enable">是否启用</param>
|
||
public void SetAdaptiveScrollbar(bool enable)
|
||
{
|
||
enableAdaptiveScrollbar = enable;
|
||
|
||
if (enable)
|
||
{
|
||
UpdateAdaptiveScrollbar();
|
||
}
|
||
else
|
||
{
|
||
// 如果禁用自适应滚动条,确保滚动条始终显示
|
||
if (verticalScrollbar != null)
|
||
{
|
||
CanvasGroup canvasGroup = verticalScrollbar.GetComponent<CanvasGroup>();
|
||
if (canvasGroup != null)
|
||
{
|
||
canvasGroup.alpha = 1f;
|
||
}
|
||
verticalScrollbar.interactable = true;
|
||
}
|
||
|
||
if (horizontalScrollbar != null)
|
||
{
|
||
CanvasGroup canvasGroup = horizontalScrollbar.GetComponent<CanvasGroup>();
|
||
if (canvasGroup != null)
|
||
{
|
||
canvasGroup.alpha = 1f;
|
||
}
|
||
horizontalScrollbar.interactable = true;
|
||
}
|
||
}
|
||
|
||
if (enableDebugLog)
|
||
{
|
||
Debug.Log($"TMPInputFieldAutoSetup: 自适应滚动条功能已{(enable ? "启用" : "禁用")}");
|
||
}
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
/// <summary>
|
||
/// 在Inspector中显示调试信息
|
||
/// </summary>
|
||
[ContextMenu("显示调试信息")]
|
||
private void ShowDebugInfo()
|
||
{
|
||
string scrollRectInfo = "";
|
||
if (scrollRect != null)
|
||
{
|
||
scrollRectInfo = $"ScrollRect: 已找到\n" +
|
||
$"Content: {(scrollRect.content != null ? "已找到" : "未找到")}\n" +
|
||
$"Content高度: {(scrollRect.content != null ? scrollRect.content.sizeDelta.y.ToString("F2") : "N/A")}\n" +
|
||
$"ContentSizeFitter: {(contentSizeFitter != null ? "已找到" : "未找到")}";
|
||
}
|
||
else
|
||
{
|
||
scrollRectInfo = "ScrollRect: 未找到";
|
||
}
|
||
|
||
Debug.Log($"TMPInputFieldAutoSetup 调试信息:\n" +
|
||
$"物体名称: {gameObject.name}\n" +
|
||
$"InputField: {(inputField != null ? "已找到" : "未找到")}\n" +
|
||
$"TextComponent: {(textComponent != null ? "已找到" : "未找到")}\n" +
|
||
$"当前文本长度: {GetTextLength()}\n" +
|
||
$"溢出模式: {overflowMode}\n" +
|
||
$"自动换行: {enableWordWrapping}\n" +
|
||
$"自动调整字体: {enableAutoSizing}\n" +
|
||
$"{scrollRectInfo}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中应用设置
|
||
/// </summary>
|
||
[ContextMenu("应用设置")]
|
||
private void ApplySettingsFromMenu()
|
||
{
|
||
AutoDetectComponents();
|
||
ApplySettings();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中设置测试文本
|
||
/// </summary>
|
||
[ContextMenu("设置测试文本")]
|
||
private void SetTestTextFromMenu()
|
||
{
|
||
string testText = "这是一个很长的测试文本,用来验证TMP InputField的显示效果。这个文本应该能够完整显示而不会被截断成省略号。如果设置正确,您应该能看到完整的文本内容,而不是以'...'结尾的截断文本。";
|
||
SetTestText(testText);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中重置为默认设置
|
||
/// </summary>
|
||
[ContextMenu("重置为默认设置")]
|
||
private void ResetToDefaultSettings()
|
||
{
|
||
overflowMode = TextOverflowModes.Page;
|
||
enableWordWrapping = true;
|
||
enableAutoSizing = false;
|
||
fontSizeMin = 12f;
|
||
fontSizeMax = 72f;
|
||
autoApplyOnAwake = true;
|
||
enableDebugLog = true;
|
||
|
||
ApplySettings();
|
||
Debug.Log("TMPInputFieldAutoSetup: 已重置为默认设置");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中手动调整Content高度
|
||
/// </summary>
|
||
[ContextMenu("调整Content高度")]
|
||
private void AdjustContentHeightFromMenu()
|
||
{
|
||
AdjustContentHeight();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中强制显示完整文本
|
||
/// </summary>
|
||
[ContextMenu("强制显示完整文本")]
|
||
private void ForceShowFullTextFromMenu()
|
||
{
|
||
ForceShowFullText();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中恢复ScrollRect滚动功能
|
||
/// </summary>
|
||
[ContextMenu("恢复滚动功能")]
|
||
private void RestoreScrollRectFromMenu()
|
||
{
|
||
RestoreScrollRectFunctionality();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中检查ScrollRect状态
|
||
/// </summary>
|
||
[ContextMenu("检查滚动状态")]
|
||
private void CheckScrollRectFromMenu()
|
||
{
|
||
CheckScrollRectStatus();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中更新自适应滚动条
|
||
/// </summary>
|
||
[ContextMenu("更新滚动条")]
|
||
private void UpdateScrollbarFromMenu()
|
||
{
|
||
UpdateAdaptiveScrollbar();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Inspector中切换自适应滚动条功能
|
||
/// </summary>
|
||
[ContextMenu("切换自适应滚动条")]
|
||
private void ToggleAdaptiveScrollbarFromMenu()
|
||
{
|
||
SetAdaptiveScrollbar(!enableAdaptiveScrollbar);
|
||
}
|
||
#endif
|
||
|
||
/// <summary>
|
||
/// 验证设置是否正确应用
|
||
/// </summary>
|
||
/// <returns>设置是否正确</returns>
|
||
public bool ValidateSettings()
|
||
{
|
||
if (textComponent == null) return false;
|
||
|
||
bool isValid = true;
|
||
|
||
// 检查溢出模式
|
||
if (textComponent.overflowMode != (TMPro.TextOverflowModes)overflowMode)
|
||
{
|
||
Debug.LogWarning($"溢出模式不匹配: 期望 {overflowMode}, 实际 {textComponent.overflowMode}");
|
||
isValid = false;
|
||
}
|
||
|
||
// 检查自动换行
|
||
if (textComponent.enableWordWrapping != enableWordWrapping)
|
||
{
|
||
Debug.LogWarning($"自动换行设置不匹配: 期望 {enableWordWrapping}, 实际 {textComponent.enableWordWrapping}");
|
||
isValid = false;
|
||
}
|
||
|
||
// 检查自动调整字体大小
|
||
if (textComponent.enableAutoSizing != enableAutoSizing)
|
||
{
|
||
Debug.LogWarning($"自动调整字体设置不匹配: 期望 {enableAutoSizing}, 实际 {textComponent.enableAutoSizing}");
|
||
isValid = false;
|
||
}
|
||
|
||
return isValid;
|
||
}
|
||
}
|