100 lines
4.2 KiB
C#
100 lines
4.2 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using TMPro;
|
||
|
||
namespace BaseGames.UI.Theme
|
||
{
|
||
/// <summary>
|
||
/// 将 <see cref="UIThemeSO"/> 中的视觉令牌应用到当前 GameObject 及其子节点。
|
||
///
|
||
/// 用法:
|
||
/// 1. 在 Prefab 根节点挂载此组件并指定 <see cref="_theme"/>;
|
||
/// 2. 在每个需要主题化的子节点添加 <see cref="UIThemeRole"/> 组件指定角色;
|
||
/// 3. <see cref="Apply"/> 会被 <see cref="OnEnable"/> 自动调用一次,
|
||
/// 也可在主题切换后手动调用。
|
||
///
|
||
/// 性能:使用 <see cref="Component.GetComponentsInChildren{T}(bool)"/> 一次性收集,
|
||
/// 仅在 Enable / 显式刷新时执行;运行时无每帧成本。
|
||
/// </summary>
|
||
[DisallowMultipleComponent]
|
||
public class UIThemeApplier : MonoBehaviour
|
||
{
|
||
[SerializeField] private UIThemeSO _theme;
|
||
[Tooltip("启用时自动应用一次。运行时切换主题可手动调用 Apply()。")]
|
||
[SerializeField] private bool _applyOnEnable = true;
|
||
|
||
private void OnEnable()
|
||
{
|
||
if (_applyOnEnable) Apply();
|
||
}
|
||
|
||
/// <summary>用当前 <see cref="_theme"/> 覆盖子节点上所有 <see cref="UIThemeRole"/> 标记。</summary>
|
||
public void Apply()
|
||
{
|
||
if (_theme == null) return;
|
||
|
||
var roles = GetComponentsInChildren<UIThemeRole>(includeInactive: true);
|
||
for (int i = 0; i < roles.Length; i++)
|
||
ApplyRole(roles[i], _theme);
|
||
}
|
||
|
||
/// <summary>运行时切换主题。</summary>
|
||
public void SetTheme(UIThemeSO theme)
|
||
{
|
||
_theme = theme;
|
||
Apply();
|
||
}
|
||
|
||
private static void ApplyRole(UIThemeRole role, UIThemeSO theme)
|
||
{
|
||
if (role == null) return;
|
||
switch (role.Kind)
|
||
{
|
||
case UIThemeRoleKind.Graphic_Primary: SetGraphicColor(role, theme.Primary); break;
|
||
case UIThemeRoleKind.Graphic_Secondary: SetGraphicColor(role, theme.Secondary); break;
|
||
case UIThemeRoleKind.Graphic_Accent: SetGraphicColor(role, theme.Accent); break;
|
||
case UIThemeRoleKind.Graphic_Background: SetGraphicColor(role, theme.Background); break;
|
||
case UIThemeRoleKind.Graphic_Success: SetGraphicColor(role, theme.Success); break;
|
||
case UIThemeRoleKind.Graphic_Warning: SetGraphicColor(role, theme.Warning); break;
|
||
case UIThemeRoleKind.Graphic_Danger: SetGraphicColor(role, theme.Danger); break;
|
||
|
||
case UIThemeRoleKind.Text_Primary: SetTextStyle(role, theme.TextPrimary, theme.BodyFont, theme.BodyFontSize); break;
|
||
case UIThemeRoleKind.Text_Secondary: SetTextStyle(role, theme.TextSecondary, theme.BodyFont, theme.SmallFontSize); break;
|
||
case UIThemeRoleKind.Text_Header: SetTextStyle(role, theme.TextPrimary, theme.HeaderFont, theme.HeaderFontSize); break;
|
||
case UIThemeRoleKind.Text_Disabled: SetTextStyle(role, theme.TextDisabled, theme.BodyFont, theme.BodyFontSize); break;
|
||
|
||
case UIThemeRoleKind.Button: SetButtonColors(role, theme); break;
|
||
}
|
||
}
|
||
|
||
private static void SetGraphicColor(UIThemeRole role, Color c)
|
||
{
|
||
var g = role.GetComponent<Graphic>();
|
||
if (g != null) g.color = c;
|
||
}
|
||
|
||
private static void SetTextStyle(UIThemeRole role, Color c, TMP_FontAsset font, float size)
|
||
{
|
||
var tmp = role.GetComponent<TMP_Text>();
|
||
if (tmp != null)
|
||
{
|
||
tmp.color = c;
|
||
if (font != null) tmp.font = font;
|
||
if (role.OverrideFontSize) tmp.fontSize = size;
|
||
}
|
||
}
|
||
|
||
private static void SetButtonColors(UIThemeRole role, UIThemeSO theme)
|
||
{
|
||
var btn = role.GetComponent<Button>();
|
||
if (btn == null) return;
|
||
var cb = btn.colors;
|
||
cb.normalColor = theme.ButtonNormal;
|
||
cb.highlightedColor = theme.ButtonHighlighted;
|
||
cb.pressedColor = theme.ButtonPressed;
|
||
cb.disabledColor = theme.ButtonDisabled;
|
||
btn.colors = cb;
|
||
}
|
||
}
|
||
}
|