Part of these game systems:
Mobile Safe Area Handler
Automatically adjusts UI RectTransform to respect device safe areas on notched phones and tablets. Supports runtime orientation changes and works across iOS and Android devices.
How to Use
1
Create a full-screen RectTransform panel as a child of your Canvas
2
Attach the MobileSafeArea script to that panel
3
Place all your UI elements inside this safe area panel
4
Toggle applyTop/Bottom/Left/Right to control which edges are inset
5
Enable simulateInEditor to preview notch behavior in the Unity editor
Source Code
C#
using UnityEngine;
[RequireComponent(typeof(RectTransform))]
public class MobileSafeArea : MonoBehaviour
{
[Header("Settings")]
[SerializeField] private bool updateContinuously = true;
[SerializeField] private bool applyTop = true;
[SerializeField] private bool applyBottom = true;
[SerializeField] private bool applyLeft = true;
[SerializeField] private bool applyRight = true;
[Header("Editor Simulation")]
[SerializeField] private bool simulateInEditor;
[SerializeField] private float simulatedNotchHeight = 80f;
private RectTransform rectTransform;
private Rect lastSafeArea;
private Vector2Int lastScreenSize;
private ScreenOrientation lastOrientation;
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
ApplySafeArea();
}
private void Update()
{
if (!updateContinuously) return;
if (HasScreenChanged())
{
ApplySafeArea();
}
}
private bool HasScreenChanged()
{
Rect safeArea = GetSafeArea();
Vector2Int screenSize = new Vector2Int(Screen.width, Screen.height);
ScreenOrientation orientation = Screen.orientation;
if (safeArea != lastSafeArea || screenSize != lastScreenSize || orientation != lastOrientation)
{
lastSafeArea = safeArea;
lastScreenSize = screenSize;
lastOrientation = orientation;
return true;
}
return false;
}
private void ApplySafeArea()
{
Rect safeArea = GetSafeArea();
if (Screen.width <= 0 || Screen.height <= 0) return;
Vector2 anchorMin = safeArea.position;
Vector2 anchorMax = safeArea.position + safeArea.size;
anchorMin.x /= Screen.width;
anchorMin.y /= Screen.height;
anchorMax.x /= Screen.width;
anchorMax.y /= Screen.height;
if (!applyLeft) anchorMin.x = 0f;
if (!applyBottom) anchorMin.y = 0f;
if (!applyRight) anchorMax.x = 1f;
if (!applyTop) anchorMax.y = 1f;
anchorMin.x = Mathf.Clamp01(anchorMin.x);
anchorMin.y = Mathf.Clamp01(anchorMin.y);
anchorMax.x = Mathf.Clamp01(anchorMax.x);
anchorMax.y = Mathf.Clamp01(anchorMax.y);
rectTransform.anchorMin = anchorMin;
rectTransform.anchorMax = anchorMax;
rectTransform.offsetMin = Vector2.zero;
rectTransform.offsetMax = Vector2.zero;
}
private Rect GetSafeArea()
{
#if UNITY_EDITOR
if (simulateInEditor)
{
return new Rect(
0f,
0f,
Screen.width,
Screen.height - simulatedNotchHeight);
}
#endif
return Screen.safeArea;
}
public void ForceUpdate()
{
ApplySafeArea();
}
public Rect GetCurrentSafeArea()
{
return GetSafeArea();
}
public Vector2 GetSafeAreaRatio()
{
Rect safe = GetSafeArea();
return new Vector2(
safe.width / Screen.width,
safe.height / Screen.height);
}
private void OnRectTransformDimensionsChange()
{
if (rectTransform != null)
ApplySafeArea();
}
private void OnValidate()
{
if (rectTransform == null)
rectTransform = GetComponent<RectTransform>();
if (rectTransform != null)
ApplySafeArea();
}
}