| | |
| | | using System; |
| | | using Cysharp.Threading.Tasks; |
| | | |
| | | [ExecuteAlways] |
| | | public class AdaptiveLayout : MonoBehaviour |
| | | [ExecuteAlways] |
| | | public class AdaptiveLayout : MonoBehaviour |
| | | { |
| | | [SerializeField] HorizonOrVertical m_HorizonOrVerticle; |
| | | [SerializeField] CanvasGroup m_CanvasGroup; |
| | | [SerializeField] List<AdaptiveElement> 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 |
| | | { |
| | | [SerializeField] HorizonOrVertical m_HorizonOrVerticle; |
| | | [SerializeField] CanvasGroup m_CanvasGroup; |
| | | [SerializeField] List<AdaptiveElement> 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<RectTransform>(); |
| | | } |
| | | 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<AdaptiveElement>(); |
| | | } |
| | | var _rect = m_AdapElements.Find((x) => |
| | | { |
| | | return x.rect == _child; |
| | | }); |
| | | var _rectOffset= _child.GetComponent<AdaptiveRectOffset>(); |
| | | 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 |
| | | { |
| | | if (m_Rect == null) |
| | | { |
| | | m_Rect = GetComponent<RectTransform>(); |
| | | } |
| | | return m_Rect; |
| | | } |
| | | } |
| | | public float Size |
| | | [SerializeField] RectOffset m_Padding; |
| | | public RectOffset padding |
| | | { |
| | | get |
| | | { |
| | | return m_HorizonOrVerticle == HorizonOrVertical.Horizon ? rectTransform.sizeDelta.x : rectTransform.sizeDelta.y; |
| | | return m_Padding; |
| | | } |
| | | } |
| | | |
| | | public event Action adaptiveUpdateEvent; |
| | | |
| | | private void OnEnable() |
| | | public AdaptiveElement(RectTransform _rect, AdaptiveRectOffset _offset) |
| | | { |
| | | if (m_AdapElements == null) |
| | | { |
| | | enabled = false; |
| | | return; |
| | | } |
| | | if (m_CanvasGroup != null) |
| | | { |
| | | m_CanvasGroup.alpha = 0; |
| | | m_CanvasGroup.interactable = true; |
| | | Co_DelayShow(); |
| | | } |
| | | m_Rect = _rect; |
| | | m_Padding = _offset == null ? new RectOffset() : _offset.rectOffset; |
| | | } |
| | | } |
| | | |
| | | 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<AdaptiveElement>(); |
| | | } |
| | | var _rect = m_AdapElements.Find((x) => |
| | | { |
| | | return x.rect == _child; |
| | | }); |
| | | var _rectOffset= _child.GetComponent<AdaptiveRectOffset>(); |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |