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
}