using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System; using Cysharp.Threading.Tasks; [ExecuteAlways] public class AdaptiveLayout : MonoBehaviour { [SerializeField] HorizonOrVertical m_HorizonOrVerticle; [SerializeField] CanvasGroup m_CanvasGroup; [SerializeField] List m_AdapElements; [SerializeField] bool m_AutoIncludeChild=false; [SerializeField] float m_LeastHeight = 0f; [SerializeField] float m_LeastWidth = 0f; [SerializeField] float m_MaxHeight = 0f; [SerializeField] float m_MaxWidth = 0f; [NonSerialized] RectTransform m_Rect; public RectTransform rectTransform { get { if (m_Rect == null) { m_Rect = GetComponent(); } return m_Rect; } } public float Size { get { return m_HorizonOrVerticle == HorizonOrVertical.Horizon ? rectTransform.sizeDelta.x : rectTransform.sizeDelta.y; } } public event Action adaptiveUpdateEvent; private void OnEnable() { if (m_AdapElements == null) { enabled = false; return; } if (m_CanvasGroup != null) { m_CanvasGroup.alpha = 0; m_CanvasGroup.interactable = true; Co_DelayShow(); } } private void TrackerRect(RectTransform _rect) { var _pivot = _rect.pivot; var _anchorMax = _rect.anchorMax; var _anchorMin = _rect.anchorMin; if (m_HorizonOrVerticle == HorizonOrVertical.Horizon) { _pivot.x = 0; _pivot.y = 0.5f; _anchorMax.x = 0; _anchorMax.y = 0.5f; _anchorMin.x = 0; _anchorMin.y = 0.5f; } else { _pivot.x = 0.5f; _pivot.y = 1f; _anchorMax.x = 0.5f; _anchorMax.y = 1; _anchorMin.x = 0.5f; _anchorMin.y = 1; } if (_rect.pivot != _pivot || _rect.anchorMax != _anchorMax || _rect.anchorMin != _anchorMin) { _rect.pivot = _pivot; _rect.anchorMax = _anchorMax; _rect.anchorMin = _anchorMin; } } private void CalculateLayout() { var _offset = 0.0f; var _horizon = m_HorizonOrVerticle == HorizonOrVertical.Horizon; for (int i = 0; i < m_AdapElements.Count; i++) { if (m_AdapElements[i].rect == null || !m_AdapElements[i].rect.gameObject.activeInHierarchy) { continue; } _offset += _horizon ? m_AdapElements[i].padding.left : m_AdapElements[i].padding.top; var _pos = m_AdapElements[i].rect.localPosition; if (_horizon) { _pos.x = _offset; } else { _pos.y = -_offset; } if (m_AdapElements[i].rect.localPosition != _pos) { m_AdapElements[i].rect.localPosition = _pos; } _offset += _horizon ? m_AdapElements[i].rect.sizeDelta.x : m_AdapElements[i].rect.sizeDelta.y; _offset += _horizon ? m_AdapElements[i].padding.right : m_AdapElements[i].padding.bottom; } var _sizeDelta = rectTransform.sizeDelta; if (_horizon) { if (m_LeastWidth > 1f) { _offset = Mathf.Max(_offset, m_LeastWidth); } if (m_MaxWidth > 1f) { _offset = Mathf.Min(_offset, m_MaxWidth); } _sizeDelta.x = _offset; } else { if (m_LeastHeight > 1f) { _offset = Mathf.Max(_offset, m_LeastHeight); } if (m_MaxHeight > 1f) { _offset = Mathf.Min(_offset, m_MaxHeight); } _sizeDelta.y = _offset; } if (rectTransform.sizeDelta != _sizeDelta) { rectTransform.sizeDelta = _sizeDelta; if (adaptiveUpdateEvent != null) { adaptiveUpdateEvent(); } } } private void LateUpdate() { if (m_AdapElements == null) { return; } TrackerRect(rectTransform); for (int i = 0; i < m_AdapElements.Count; i++) { if (m_AdapElements[i].rect == null) { continue; } TrackerRect(m_AdapElements[i].rect); } CalculateLayout(); } private void OnTransformChildrenChanged() { if (m_AutoIncludeChild) { AutoIncludeChild(); } } private void AutoIncludeChild() { var _index = 0; foreach (Transform _child in transform) { if (m_AdapElements == null) { m_AdapElements = new List(); } var _rect = m_AdapElements.Find((x) => { return x.rect == _child; }); var _rectOffset= _child.GetComponent(); if (_rect == null) { m_AdapElements.Insert(_index, new AdaptiveElement(_child as RectTransform, _rectOffset)); } _index++; } if (m_AdapElements != null) { m_AdapElements.RemoveAll((x) => { return x.rect == null; }); } LateUpdate(); } async UniTask Co_DelayShow() { await UniTask.Delay(100); if (m_CanvasGroup != null) { m_CanvasGroup.alpha = 1; } } public enum HorizonOrVertical { Horizon, Vertical, } [Serializable] public class AdaptiveElement { [SerializeField] RectTransform m_Rect; public RectTransform rect { get { return m_Rect; } } [SerializeField] RectOffset m_Padding; public RectOffset padding { get { return m_Padding; } } public AdaptiveElement(RectTransform _rect, AdaptiveRectOffset _offset) { m_Rect = _rect; m_Padding = _offset == null ? new RectOffset() : _offset.rectOffset; } } }