using UnityEngine; /// /// 安全区域适配组件 - 自动适配刘海屏和异形屏 /// [RequireComponent(typeof(RectTransform))] [ExecuteInEditMode] public class SafeAreaAdapter : MonoBehaviour { [Header("适配设置")] [Tooltip("是否在编辑器模式下模拟安全区域")] public bool simulateInEditor = false; [Tooltip("适配边缘(Top, Bottom, Left, Right)")] public bool adaptTop = true; public bool adaptBottom = true; public bool adaptLeft = true; public bool adaptRight = true; [Header("调试信息")] [SerializeField] private Rect currentSafeArea; [SerializeField] private Vector2Int screenSize; private RectTransform _rectTransform; private Rect _lastSafeArea = Rect.zero; private Vector2Int _lastScreenSize = Vector2Int.zero; private void Awake() { _rectTransform = GetComponent(); ApplySafeArea(); } private void Update() { // 检测屏幕变化或安全区域变化 if (HasScreenChanged()) { ApplySafeArea(); } } /// /// 检测屏幕是否发生变化 /// private bool HasScreenChanged() { Rect safeArea = GetSafeArea(); Vector2Int screenSize = new Vector2Int(Screen.width, Screen.height); bool changed = safeArea != _lastSafeArea || screenSize != _lastScreenSize; _lastSafeArea = safeArea; _lastScreenSize = screenSize; return changed; } /// /// 获取安全区域 /// private Rect GetSafeArea() { #if UNITY_EDITOR if (simulateInEditor) { // 编辑器模式下模拟 iPhone X 的安全区域 float screenWidth = Screen.width; float screenHeight = Screen.height; // 模拟刘海(顶部 44px)和底部手势条(底部 34px) float topInset = 44f; float bottomInset = 34f; float leftInset = 0f; float rightInset = 0f; return new Rect( leftInset, bottomInset, screenWidth - leftInset - rightInset, screenHeight - topInset - bottomInset ); } #endif return Screen.safeArea; } /// /// 应用安全区域适配 /// private void ApplySafeArea() { if (_rectTransform == null) return; Rect safeArea = GetSafeArea(); currentSafeArea = safeArea; screenSize = new Vector2Int(Screen.width, Screen.height); // 计算锚点位置 Vector2 anchorMin = safeArea.position; Vector2 anchorMax = safeArea.position + safeArea.size; // 转换为标准化坐标 (0-1) anchorMin.x /= Screen.width; anchorMin.y /= Screen.height; anchorMax.x /= Screen.width; anchorMax.y /= Screen.height; // 根据设置决定是否适配各个边缘 Vector2 finalAnchorMin = _rectTransform.anchorMin; Vector2 finalAnchorMax = _rectTransform.anchorMax; if (adaptLeft) finalAnchorMin.x = anchorMin.x; if (adaptBottom) finalAnchorMin.y = anchorMin.y; if (adaptRight) finalAnchorMax.x = anchorMax.x; if (adaptTop) finalAnchorMax.y = anchorMax.y; _rectTransform.anchorMin = finalAnchorMin; _rectTransform.anchorMax = finalAnchorMax; // 重置偏移 _rectTransform.offsetMin = Vector2.zero; _rectTransform.offsetMax = Vector2.zero; Debug.Log($"[SafeAreaAdapter] 安全区域已应用: {safeArea}, 屏幕: {screenSize}"); } /// /// 强制重新应用安全区域 /// public void ForceApply() { ApplySafeArea(); } #if UNITY_EDITOR private void OnValidate() { if (_rectTransform == null) _rectTransform = GetComponent(); ApplySafeArea(); } #endif }