using System;
|
using System.Collections.Generic;
|
using UnityEngine;
|
using UnityEngine.UI;
|
|
/// <summary>
|
/// 文本组件类型枚举
|
/// </summary>
|
public enum TextComponentType
|
{
|
None = 0,
|
Text = 1,
|
TextEx = 2,
|
GradientText = 3
|
}
|
|
/// <summary>
|
/// 多语言排版配置项,存储单个语言的布局和适配数据
|
/// </summary>
|
[Serializable]
|
public class LanguageConfigItem
|
{
|
// ============ RectTransform 配置 ============
|
[Header("RectTransform 配置")]
|
public Vector2 anchoredPosition = Vector2.zero;
|
public Vector2 sizeDelta = new Vector2(100f, 30f);
|
public Vector2 anchorMin = new Vector2(0.5f, 0.5f);
|
public Vector2 anchorMax = new Vector2(0.5f, 0.5f);
|
public Vector2 pivot = new Vector2(0.5f, 0.5f);
|
public Vector3 localScale = Vector3.one;
|
public Vector3 localRotation = Vector3.zero;
|
|
// ============ Text 排版与适配配置 ============
|
[Header("Text 排版与适配配置")]
|
public Font font;
|
public FontStyle fontStyle = FontStyle.Normal;
|
public int fontSize = 14;
|
public float lineSpacing = 1f;
|
|
public HorizontalWrapMode horizontalOverflow = HorizontalWrapMode.Wrap;
|
public VerticalWrapMode verticalOverflow = VerticalWrapMode.Truncate;
|
|
public bool resizeTextForBestFit = false;
|
public int resizeTextMinSize = 10;
|
public int resizeTextMaxSize = 40;
|
|
public TextAnchor alignment = TextAnchor.UpperLeft;
|
public bool alignByGeometry = false;
|
|
/// <summary> 将配置应用到 RectTransform </summary>
|
public void ApplyToRectTransform(RectTransform rectTransform)
|
{
|
if (rectTransform == null) return;
|
rectTransform.anchorMin = anchorMin;
|
rectTransform.anchorMax = anchorMax;
|
rectTransform.pivot = pivot;
|
rectTransform.anchoredPosition = anchoredPosition;
|
rectTransform.sizeDelta = sizeDelta;
|
rectTransform.localScale = localScale;
|
rectTransform.localRotation = Quaternion.Euler(localRotation);
|
}
|
|
/// <summary> 从 RectTransform 读取配置 </summary>
|
public void ReadFromRectTransform(RectTransform rectTransform)
|
{
|
if (rectTransform == null) return;
|
anchorMin = rectTransform.anchorMin;
|
anchorMax = rectTransform.anchorMax;
|
pivot = rectTransform.pivot;
|
anchoredPosition = rectTransform.anchoredPosition;
|
sizeDelta = rectTransform.sizeDelta;
|
localScale = rectTransform.localScale;
|
localRotation = rectTransform.localRotation.eulerAngles;
|
}
|
|
/// <summary> 将配置应用到 Text </summary>
|
public void ApplyToText(Text textComponent)
|
{
|
if (textComponent == null) return;
|
if (font != null) textComponent.font = font;
|
|
textComponent.fontStyle = fontStyle;
|
textComponent.fontSize = fontSize;
|
textComponent.lineSpacing = lineSpacing;
|
textComponent.horizontalOverflow = horizontalOverflow;
|
textComponent.verticalOverflow = verticalOverflow;
|
textComponent.resizeTextForBestFit = resizeTextForBestFit;
|
|
if (resizeTextForBestFit)
|
{
|
textComponent.resizeTextMinSize = resizeTextMinSize;
|
textComponent.resizeTextMaxSize = resizeTextMaxSize;
|
}
|
|
textComponent.alignment = alignment;
|
textComponent.alignByGeometry = alignByGeometry;
|
}
|
|
/// <summary> 从 Text 读取配置 </summary>
|
public void ReadFromText(Text textComponent)
|
{
|
if (textComponent == null) return;
|
font = textComponent.font;
|
fontStyle = textComponent.fontStyle;
|
fontSize = textComponent.fontSize;
|
lineSpacing = textComponent.lineSpacing;
|
horizontalOverflow = textComponent.horizontalOverflow;
|
verticalOverflow = textComponent.verticalOverflow;
|
resizeTextForBestFit = textComponent.resizeTextForBestFit;
|
resizeTextMinSize = textComponent.resizeTextMinSize;
|
resizeTextMaxSize = textComponent.resizeTextMaxSize;
|
alignment = textComponent.alignment;
|
alignByGeometry = textComponent.alignByGeometry;
|
}
|
|
/// <summary>
|
/// 快速克隆配置
|
/// 由于内部均为值类型或需浅拷贝的引用(Font),可以直接使用 MemberwiseClone
|
/// </summary>
|
public LanguageConfigItem Clone()
|
{
|
return (LanguageConfigItem)this.MemberwiseClone();
|
}
|
}
|
|
/// <summary>
|
/// 语言配置字典(Unity 内置序列化支持的双 List 结构)
|
/// </summary>
|
[Serializable]
|
public class LanguageConfigDictionary
|
{
|
public List<string> keys = new List<string>();
|
public List<LanguageConfigItem> values = new List<LanguageConfigItem>();
|
|
public LanguageConfigItem Get(string key)
|
{
|
if (string.IsNullOrEmpty(key)) return null;
|
int index = keys.IndexOf(key);
|
return (index >= 0 && index < values.Count) ? values[index] : null;
|
}
|
|
public void Set(string key, LanguageConfigItem value)
|
{
|
int index = keys.IndexOf(key);
|
if (index >= 0 && index < values.Count)
|
{
|
values[index] = value;
|
}
|
else
|
{
|
keys.Add(key);
|
values.Add(value);
|
}
|
}
|
|
public bool ContainsKey(string key) => keys.Contains(key);
|
|
public void Remove(string key)
|
{
|
int index = keys.IndexOf(key);
|
if (index >= 0)
|
{
|
keys.RemoveAt(index);
|
if (index < values.Count) values.RemoveAt(index);
|
}
|
}
|
}
|
|
/// <summary>
|
/// 文本多语言排版适配组件
|
/// </summary>
|
[RequireComponent(typeof(RectTransform))]
|
public class TextLanguageAdapter : MonoBehaviour
|
{
|
public const string DefaultLangId = "default"; // 提取常量避免硬编码错误
|
|
[SerializeField]
|
[Tooltip("每种语言的配置,使用语言ID作为key(如zh、en、ft),default为默认配置")]
|
private LanguageConfigDictionary m_LanguageConfigs = new LanguageConfigDictionary();
|
|
[SerializeField]
|
[Tooltip("自动检测到的文本组件类型")]
|
private TextComponentType m_TargetTextType = TextComponentType.None;
|
|
[SerializeField]
|
[Tooltip("关联的文本组件引用")]
|
private Component m_TargetTextComponent;
|
|
private bool m_IsApplied = false;
|
|
#region 公共属性
|
public TextComponentType TargetTextType => m_TargetTextType;
|
public Component TargetTextComponent => m_TargetTextComponent; // 开放给 Editor 使用,避免反射
|
public LanguageConfigDictionary LanguageConfigs => m_LanguageConfigs;
|
#endregion
|
|
#region Unity生命周期
|
protected void Awake()
|
{
|
DetectTargetComponent();
|
}
|
|
protected void OnEnable()
|
{
|
// 保证仅应用一次排版以节省性能,除非在编辑器非运行模式下需要强刷
|
if (!Application.isPlaying || !m_IsApplied)
|
{
|
string langId = Application.isPlaying ? Language.Id : DefaultLangId;
|
ApplyConfig(langId);
|
}
|
}
|
|
#if UNITY_EDITOR
|
protected void Reset()
|
{
|
DetectTargetComponent();
|
if (!HasConfig(DefaultLangId))
|
{
|
ReadCurrentToConfig(DefaultLangId);
|
}
|
}
|
#endif
|
#endregion
|
|
#region 公共配置方法
|
public LanguageConfigItem GetConfig(string languageId)
|
{
|
// 1. 尝试获取目标语言配置
|
LanguageConfigItem config = m_LanguageConfigs.Get(languageId);
|
if (config != null) return config;
|
|
// 2. 找不到则回退到默认配置
|
config = m_LanguageConfigs.Get(DefaultLangId);
|
if (config != null) return config;
|
|
Debug.LogError($"[TextLanguageAdapter] 找不到语言 {languageId} 的配置,且不存在 default 默认配置!");
|
return null;
|
}
|
|
public void SetConfig(string languageId, LanguageConfigItem config) => m_LanguageConfigs.Set(languageId, config);
|
public void RemoveConfig(string languageId) => m_LanguageConfigs.Remove(languageId);
|
public bool HasConfig(string languageId) => m_LanguageConfigs.ContainsKey(languageId);
|
public List<string> GetConfiguredLanguages() => new List<string>(m_LanguageConfigs.keys);
|
|
public void ApplyConfig(string languageId)
|
{
|
LanguageConfigItem config = GetConfig(languageId);
|
if (config == null) return;
|
|
if (TryGetComponent(out RectTransform rectTransform))
|
config.ApplyToRectTransform(rectTransform);
|
|
if (m_TargetTextComponent is Text textComponent)
|
config.ApplyToText(textComponent);
|
|
m_IsApplied = true;
|
}
|
|
public void ReadCurrentToConfig(string languageId)
|
{
|
LanguageConfigItem config = new LanguageConfigItem();
|
|
if (TryGetComponent(out RectTransform rectTransform))
|
config.ReadFromRectTransform(rectTransform);
|
|
if (m_TargetTextComponent is Text textComponent)
|
config.ReadFromText(textComponent);
|
|
SetConfig(languageId, config);
|
}
|
|
public static string GetLanguageShowName(string languageId)
|
{
|
if (Language.languageShowDict != null && Language.languageShowDict.TryGetValue(languageId, out string showName))
|
{
|
return showName;
|
}
|
return languageId;
|
}
|
#endregion
|
|
#region 私有组件检测
|
private void DetectTargetComponent()
|
{
|
if (m_TargetTextComponent != null)
|
{
|
DetermineTextType(m_TargetTextComponent);
|
return;
|
}
|
|
// 按优先级查找组件
|
m_TargetTextComponent = FindComponent<GradientText>()
|
?? FindComponent<TextEx>()
|
?? (Component)FindComponent<Text>();
|
|
DetermineTextType(m_TargetTextComponent);
|
}
|
|
/// <summary> 辅助方法:在自身和子物体中查找组件 </summary>
|
private T FindComponent<T>() where T : Component
|
{
|
T comp = GetComponent<T>();
|
return comp != null ? comp : GetComponentInChildren<T>(true);
|
}
|
|
private void DetermineTextType(Component component)
|
{
|
m_TargetTextType = component switch
|
{
|
GradientText _ => TextComponentType.GradientText,
|
TextEx _ => TextComponentType.TextEx,
|
Text _ => TextComponentType.Text,
|
_ => TextComponentType.None
|
};
|
}
|
#endregion
|
|
#if UNITY_EDITOR
|
[ContextMenu("刷新组件检测")]
|
public void Editor_ForceRefreshDetection()
|
{
|
DetectTargetComponent();
|
UnityEditor.EditorUtility.SetDirty(this);
|
}
|
|
[ContextMenu("读取当前配置")]
|
public void Editor_ReadCurrentConfig()
|
{
|
ReadCurrentToConfig(DefaultLangId);
|
UnityEditor.EditorUtility.SetDirty(this);
|
}
|
|
[ContextMenu("应用默认配置")]
|
public void Editor_ApplyDefaultConfig()
|
{
|
ApplyConfig(DefaultLangId);
|
}
|
#endif
|
}
|