yyl
2025-08-11 b2d7bb59dc37c7b350786b076ee2f344b7c8911f
Main/Component/UI/Common/AdaptiveLayout.cs
@@ -5,236 +5,236 @@
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;
            }
        }
    }
}