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;
|
try
|
{
|
img.alphaHitTestMinimumThreshold = alphaHitTestMinimumThreshold;
|
}
|
catch (InvalidOperationException)
|
{
|
// 纹理不可读或未使用 Crunch 压缩时跳过,这是 Unity 内部限制
|
}
|
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
|
}
|