lcy
2 天以前 be3c8bf7cbef98b3ada4067954ad4286730c727f
592 多语言适配 提交主干
1个文件已修改
2个文件已添加
331 ■■■■■ 已修改文件
Main/Component/UI/Core/ImageLanguageAdapter.cs 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Core/ImageLanguageAdapter.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Core/TextLanguageAdapter.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Core/ImageLanguageAdapter.cs
New file
@@ -0,0 +1,279 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 图片组件类型枚举
/// </summary>
public enum ImageComponentType
{
    None = 0,
    Image = 1,
    ImageEx = 2
}
/// <summary>
/// 单个语言的图片排版和适配数据节点
/// </summary>
[Serializable]
public class ImageLanguageConfigItem
{
    [Header("RectTransform 配置")]
    public Vector2 anchoredPosition = Vector2.zero;
    public Vector2 sizeDelta = new Vector2(100f, 100f);
    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;
    [Header("Image 配置")]
    public bool enabled = true;
    public Color color = Color.white;
    public Image.Type type = Image.Type.Simple;
    public bool fillCenter = true;
    public Image.FillMethod fillMethod = Image.FillMethod.Horizontal;
    public float fillAmount = 1f;
    public int fillOrigin = 0;
    public bool preserveAspect = true;
    public float alphaHitTestMinimumThreshold = 0f;
    public bool useSpriteMesh = false;
    public float pixelsPerUnitMultiplier = 1f;
    public void ApplyToRectTransform(RectTransform rt)
    {
        if (rt == null) return;
        rt.anchorMin = anchorMin;
        rt.anchorMax = anchorMax;
        rt.pivot = pivot;
        rt.anchoredPosition = anchoredPosition;
        rt.sizeDelta = sizeDelta;
        rt.localScale = localScale;
        rt.localRotation = Quaternion.Euler(localRotation);
    }
    public void ReadFromRectTransform(RectTransform rt)
    {
        if (rt == null) return;
        anchorMin = rt.anchorMin;
        anchorMax = rt.anchorMax;
        pivot = rt.pivot;
        anchoredPosition = rt.anchoredPosition;
        sizeDelta = rt.sizeDelta;
        localScale = rt.localScale;
        localRotation = rt.localRotation.eulerAngles;
    }
    public void ApplyToImage(Image img)
    {
        if (img == null) return;
        img.color = color;
        img.type = type;
        img.fillCenter = fillCenter;
        img.fillMethod = fillMethod;
        img.fillAmount = fillAmount;
        img.fillOrigin = fillOrigin;
        img.preserveAspect = preserveAspect;
        img.alphaHitTestMinimumThreshold = alphaHitTestMinimumThreshold;
        img.useSpriteMesh = useSpriteMesh;
        img.pixelsPerUnitMultiplier = pixelsPerUnitMultiplier;
    }
    public void ReadFromImage(Image img)
    {
        if (img == null) return;
        color = img.color;
        type = img.type;
        fillCenter = img.fillCenter;
        fillMethod = img.fillMethod;
        fillAmount = img.fillAmount;
        fillOrigin = img.fillOrigin;
        preserveAspect = img.preserveAspect;
        alphaHitTestMinimumThreshold = img.alphaHitTestMinimumThreshold;
        useSpriteMesh = img.useSpriteMesh;
        pixelsPerUnitMultiplier = img.pixelsPerUnitMultiplier;
    }
    public ImageLanguageConfigItem Clone() => (ImageLanguageConfigItem)MemberwiseClone();
}
/// <summary>
/// 支持 Unity 序列化的字典
/// </summary>
[Serializable]
public class ImageLanguageConfigDictionary
{
    public List<string> keys = new List<string>();
    public List<ImageLanguageConfigItem> values = new List<ImageLanguageConfigItem>();
    public ImageLanguageConfigItem Get(string key)
    {
        if (string.IsNullOrEmpty(key)) return null;
        int index = keys.IndexOf(key);
        return index >= 0 ? values[index] : null;
    }
    public void Set(string key, ImageLanguageConfigItem value)
    {
        int index = keys.IndexOf(key);
        if (index >= 0) 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);
            values.RemoveAt(index);
        }
    }
}
/// <summary>
/// 多语言图片排版适配器
/// </summary>
[RequireComponent(typeof(RectTransform))]
public class ImageLanguageAdapter : MonoBehaviour
{
    public const string DefaultLangId = "default";
    [SerializeField, Tooltip("语言配置字典")]
    private ImageLanguageConfigDictionary m_LanguageConfigs = new ImageLanguageConfigDictionary();
    [SerializeField, Tooltip("目标图片组件类型")]
    private ImageComponentType m_TargetImageType = ImageComponentType.None;
    [SerializeField, Tooltip("关联的图片组件引用")]
    private Component m_TargetImageComponent;
    private bool m_IsApplied = false;
    public ImageComponentType TargetImageType
    {
        get => m_TargetImageType;
        set => m_TargetImageType = value;
    }
    public Component TargetImageComponent
    {
        get => m_TargetImageComponent;
        set => m_TargetImageComponent = value;
    }
    public ImageLanguageConfigDictionary LanguageConfigs => m_LanguageConfigs;
    private void Awake() => DetectTargetComponent();
    private void OnEnable()
    {
        if (!Application.isPlaying || !m_IsApplied)
        {
            string langId = Application.isPlaying ? Language.Id : DefaultLangId;
            ApplyConfig(langId);
        }
    }
#if UNITY_EDITOR
    private void Reset()
    {
        DetectTargetComponent();
        if (!HasConfig(DefaultLangId)) ReadCurrentToConfig(DefaultLangId);
    }
#endif
    public ImageLanguageConfigItem GetConfig(string languageId) => m_LanguageConfigs.Get(languageId);
    public void SetConfig(string languageId, ImageLanguageConfigItem 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)
    {
        var config = GetConfig(languageId);
        if (config == null) return;
        config.ApplyToRectTransform(GetComponent<RectTransform>());
        if (m_TargetImageComponent != null)
        {
            m_TargetImageComponent.gameObject.SetActive(config.enabled);
        }
        if (m_TargetImageComponent is Image img)
        {
            config.ApplyToImage(img);
        }
        m_IsApplied = true;
    }
    public void ReadCurrentToConfig(string languageId)
    {
        var config = new ImageLanguageConfigItem();
        config.ReadFromRectTransform(GetComponent<RectTransform>());
        if (m_TargetImageComponent is Image img)
        {
            config.ReadFromImage(img);
        }
        SetConfig(languageId, config);
    }
    public static string GetLanguageShowName(string languageId)
    {
        if (Language.languageShowDict != null && Language.languageShowDict.TryGetValue(languageId, out string showName))
            return showName;
        return languageId;
    }
    private void DetectTargetComponent()
    {
        if (m_TargetImageComponent != null)
        {
            DetermineImageType(m_TargetImageComponent);
            return;
        }
        m_TargetImageComponent = GetComponent<ImageEx>() ?? GetComponentInChildren<ImageEx>(true) as Component
                                ?? GetComponent<Image>() ?? GetComponentInChildren<Image>(true) as Component;
        DetermineImageType(m_TargetImageComponent);
    }
    private void DetermineImageType(Component component)
    {
        m_TargetImageType = component switch
        {
            ImageEx _ => ImageComponentType.ImageEx,
            Image _ => ImageComponentType.Image,
            _ => ImageComponentType.None
        };
    }
#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
}
Main/Component/UI/Core/ImageLanguageAdapter.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ca83c0f98acaca459051c33bb4270dd
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Component/UI/Core/TextLanguageAdapter.cs
@@ -156,6 +156,8 @@
    private bool m_IsApplied = false;
    private void Awake() => DetectTargetComponent();
    // 开放 set 权限,允许外部或编辑器手动赋值
    public TextComponentType TargetTextType 
    { 
@@ -186,6 +188,32 @@
    public bool HasConfig(string languageId) => m_LanguageConfigs.ContainsKey(languageId);
    public List<string> GetConfiguredLanguages() => new List<string>(m_LanguageConfigs.keys);
    private void DetectTargetComponent()
    {
        if (m_TargetTextComponent != null)
        {
            DetermineTextType(m_TargetTextComponent);
            return;
        }
        m_TargetTextComponent = GetComponent<TextEx>() ?? GetComponentInChildren<TextEx>(true) as Component
                                ?? GetComponent<GradientText>() ?? GetComponentInChildren<GradientText>(true) as Component
                                ?? GetComponent<Text>() ?? GetComponentInChildren<Text>(true) as Component;
        DetermineTextType(m_TargetTextComponent);
    }
    private void DetermineTextType(Component component)
    {
        m_TargetTextType = component switch
        {
            TextEx _ => TextComponentType.TextEx,
            GradientText _ => TextComponentType.GradientText,
            Text _ => TextComponentType.Text,
            _ => TextComponentType.None
        };
    }
    public void ApplyConfig(string languageId)
    {
        var config = GetConfig(languageId);
@@ -214,6 +242,19 @@
    }
#if UNITY_EDITOR
    private void Reset()
    {
        DetectTargetComponent();
        if (!HasConfig(DefaultLangId)) ReadCurrentToConfig(DefaultLangId);
    }
    [ContextMenu("刷新组件检测")]
    public void Editor_ForceRefreshDetection()
    {
        DetectTargetComponent();
        UnityEditor.EditorUtility.SetDirty(this);
    }
    [ContextMenu("读取当前配置")]
    public void Editor_ReadCurrentConfig()
    {