【Unity】LayoutGroup自动缩放子对象大小

需求:
如果LayoutGroup的子物体太多,超出layoutGroup的范围,则对子物体进行缩小。确保子物体都在LayoutGroup的范围内

代码:


[ExecuteInEditMode]
[RequireComponent(typeof(HorizontalOrVerticalLayoutGroup))]
public class LayoutGroupChildFitter : MonoBehaviour, ILayoutController
{
    [Header("最小缩放尺寸,小于0的话脚本失效")]
    public float m_minChildSize = -1f;
    [Header("是否为水平布局")]
    public bool m_isHorizontal = true;
    //layoutGroup
    [SerializeField] HorizontalOrVerticalLayoutGroup m_layout = null;
    [SerializeField] RectTransform m_rectTransform;
    float m_curScale = 0;

    //子节点
    List<RectTransform> m_rectChildren = new List<RectTransform>();
    private void Start()
    {
        if (m_layout == null)
            m_layout = this.transform.GetComponent<HorizontalOrVerticalLayoutGroup>();
        if (m_rectTransform == null) 
            m_rectTransform = this.GetComponent<RectTransform>();
        DoFixChildSize();

    }


    void ILayoutController.SetLayoutHorizontal()
    {
        if (m_layout == null)
            m_layout = this.transform.GetComponent<HorizontalOrVerticalLayoutGroup>();
        if (m_rectTransform == null)
            m_rectTransform = this.GetComponent<RectTransform>();
        DoFixChildSize();
    }

    void ILayoutController.SetLayoutVertical()
    {
        if (m_layout == null)
            m_layout = this.transform.GetComponent<HorizontalOrVerticalLayoutGroup>();
        if (m_rectTransform == null)
            m_rectTransform = this.GetComponent<RectTransform>();
        DoFixChildSize();
    }

    /// 
    /// 子节点缩放
    /// 
    void DoFixChildSize()
    {
        if (m_minChildSize < 0) return;
        GetRectChildren();
        float childrenSize = GetChildrenTotalSize();
        float contentSize = GetContentSize();
        float scale = contentSize / childrenSize;
        scale = Mathf.Clamp(scale, m_minChildSize, 1);
        if (m_curScale != scale)
        {
            Debug.Log($"Layout Child 缩放{contentSize}/{childrenSize}=scale:{scale}");
            Vector3 localScale = Vector3.one * scale;
            SetChildrenChild(localScale);
            m_curScale = scale;
            LayoutRebuilder.ForceRebuildLayoutImmediate(m_rectTransform);
        }
    }

    /// 
    /// 把所有子节点设置
    /// 
    /// 
    void SetChildrenChild(Vector3 localScale)
    {
        for (int i = 0; i < m_rectChildren.Count; i++)
        {
            m_rectChildren[i].localScale = localScale;
        }
    }

    /// 
    /// 计算容器尺寸
    /// 
    /// 
    float GetContentSize()
    {
        float size = (m_isHorizontal) ? m_rectTransform.rect.width : m_rectTransform.rect.height;
        //边距
        float padding = (m_isHorizontal) ?
            m_layout.padding.right + m_layout.padding.left :
            m_layout.padding.top + m_layout.padding.bottom;
        //总间距
        float spacing = (m_rectChildren.Count - 1) * m_layout.spacing;
        return size - padding - spacing;
    }

    /// 
    /// 计算子物体总尺寸
    /// 
    /// 
    float GetChildrenTotalSize()
    {

        //总长度
        float total = 0;
        for (int i = 0; i < m_rectChildren.Count; i++)
        {
            if (!m_rectChildren[i].gameObject.activeInHierarchy) continue;  //不考虑隐藏
            if (m_isHorizontal) total += m_rectChildren[i].sizeDelta.x;
            else total += m_rectChildren[i].sizeDelta.y;
        }

        return total;
    }


    /// 
    /// 获取子物体
    /// 
    void GetRectChildren()
    {
        if (transform.childCount == m_rectChildren.Count) return;
        m_rectChildren.Clear();
        for (int i = 0; i < transform.childCount; i++)
        {
            RectTransform rect = transform.GetChild(i).GetComponent<RectTransform>();
            if (!m_rectChildren.Contains(rect)) m_rectChildren.Add(rect);
        }
    }
}

你可能感兴趣的:(unity,UGUI,unity,游戏引擎)