Files
zeling_v2/Assets/_Game/Scripts/UI/Utility/UIScaleApplier.cs
2026-05-25 13:21:41 +08:00

68 lines
2.3 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using BaseGames.Core;
namespace BaseGames.UI
{
/// <summary>
/// 将 <see cref="ISettingsService"/>.<c>Current.UIScale</c> 应用到挂载的
/// <see cref="CanvasScaler"/>。挂在每个根 Canvas 上即可。
///
/// 实现要点:
/// · 记录 Inspector 初始的 <c>scaleFactor</c> / <c>referenceResolution</c> 作为基准值,
/// 避免反复缩放导致的累积漂移;
/// · 订阅 <see cref="SettingsManager.SettingsChanged"/> 在玩家调整后即时刷新;
/// · 兼容 <see cref="CanvasScaler.ScaleMode.ScaleWithScreenSize"/> 与
/// <see cref="CanvasScaler.ScaleMode.ConstantPixelSize"/> 两种模式。
/// </summary>
[DisallowMultipleComponent]
[RequireComponent(typeof(CanvasScaler))]
public class UIScaleApplier : MonoBehaviour
{
private CanvasScaler _scaler;
private float _baseScaleFactor;
private Vector2 _baseReferenceResolution;
private void Awake()
{
_scaler = GetComponent<CanvasScaler>();
_baseScaleFactor = _scaler.scaleFactor;
_baseReferenceResolution = _scaler.referenceResolution;
}
private void OnEnable()
{
SettingsManager.SettingsChanged += OnSettingsChanged;
Apply();
}
private void OnDisable()
{
SettingsManager.SettingsChanged -= OnSettingsChanged;
}
private void OnSettingsChanged(GlobalSettingsData _) => Apply();
private void Apply()
{
var svc = ServiceLocator.GetOrDefault<ISettingsService>();
float ui = svc?.Current?.UIScale ?? 1f;
if (ui <= 0f) ui = 1f;
switch (_scaler.uiScaleMode)
{
case CanvasScaler.ScaleMode.ConstantPixelSize:
_scaler.scaleFactor = _baseScaleFactor * ui;
break;
case CanvasScaler.ScaleMode.ScaleWithScreenSize:
// 缩小参考分辨率 → 等价于放大 UI。
_scaler.referenceResolution = _baseReferenceResolution / ui;
break;
default:
_scaler.scaleFactor = _baseScaleFactor * ui;
break;
}
}
}
}