using System; using System.Collections; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace E7.NotchSolution { /// /// A base class to derive from if you want to make a notch-aware component. /// will be called at the "correct moment". /// You change the as you like in there. /// /// /// It helps you store the simulated values from Notch Simulator and expose them as `protected` fields. /// Plus you can use to travel to the closest that is /// this component's parent. Usually you will want to do something related to the "entire screen". /// [DisallowMultipleComponent] [RequireComponent(typeof(RectTransform))] public abstract class NotchSolutionUIBehaviourBase : UIBehaviour, ILayoutSelfController, INotchSimulatorTarget { private readonly WaitForEndOfFrame eofWait = new WaitForEndOfFrame(); [NonSerialized] private RectTransform m_Rect; protected DrivenRectTransformTracker m_Tracker; private Rect[] storedSimulatedCutoutsRelative = NotchSolutionUtility.defaultCutouts; private Rect storedSimulatedSafeAreaRelative = NotchSolutionUtility.defaultSafeArea; /// /// Already taken account whether should trust Notch Simulator /// or Unity's [Device Simulator package](https://docs.unity3d.com/Packages/com.unity.device-simulator@latest/). /// protected Rect SafeAreaRelative => NotchSolutionUtility.ShouldUseNotchSimulatorValue ? storedSimulatedSafeAreaRelative : NotchSolutionUtility.ScreenSafeAreaRelative; protected RectTransform rectTransform { get { if (m_Rect == null) { m_Rect = GetComponent(); } return m_Rect; } } /// /// Overrides /// protected override void OnEnable() { base.OnEnable(); DelayedUpdate(); } /// /// Overrides /// protected override void OnDisable() { m_Tracker.Clear(); LayoutRebuilder.MarkLayoutForRebuild(rectTransform); base.OnDisable(); } /// /// Overrides . /// This doesn't work when flipping the orientation to opposite side (180 deg). /// It only works for 90 deg. rotation because that makes the rect transform changes dimension. /// protected override void OnRectTransformDimensionsChange() { UpdateRectBase(); } void ILayoutController.SetLayoutHorizontal() { UpdateRectBase(); } void ILayoutController.SetLayoutVertical() { } void INotchSimulatorTarget.SimulatorUpdate(Rect simulatedSafeAreaRelative, Rect[] simulatedCutoutsRelative) { storedSimulatedSafeAreaRelative = simulatedSafeAreaRelative; storedSimulatedCutoutsRelative = simulatedCutoutsRelative; UpdateRectBase(); } protected abstract void UpdateRect(); protected Rect GetCanvasRect() { var topLevelCanvas = GetTopLevelCanvas(); var topRectSize = topLevelCanvas.GetComponent().sizeDelta; return new Rect(Vector2.zero, topRectSize); Canvas GetTopLevelCanvas() { var canvas = GetComponentInParent(); var rootCanvas = canvas.rootCanvas; return rootCanvas; } } private void UpdateRectBase() { if (!(enabled && gameObject.activeInHierarchy)) { return; } UpdateRect(); } private void DelayedUpdate() { StartCoroutine(DelayedUpdateRoutine()); } private IEnumerator DelayedUpdateRoutine() { yield return eofWait; UpdateRectBase(); } #if UNITY_EDITOR /// /// Overrides . /// protected override void Reset() { base.Reset(); } /// /// Overrides . /// protected override void OnValidate() { if (gameObject.activeInHierarchy) { DelayedUpdate(); } } #endif } }