namespace UnityEngine.UI { // 布局算法的核心都在这个基类里面 public abstract class HorizontalOrVerticalLayoutGroup : LayoutGroup { [SerializeField] protected float m_Spacing = 0; public float spacing { get { return m_Spacing; } set { SetProperty(ref m_Spacing, value); } } [SerializeField] protected bool m_ChildForceExpandWidth = true; public bool childForceExpandWidth { get { return m_ChildForceExpandWidth; } set { SetProperty(ref m_ChildForceExpandWidth, value); } } [SerializeField] protected bool m_ChildForceExpandHeight = true; public bool childForceExpandHeight { get { return m_ChildForceExpandHeight; } set { SetProperty(ref m_ChildForceExpandHeight, value); } } [SerializeField] protected bool m_ChildControlWidth = true; public bool childControlWidth { get { return m_ChildControlWidth; } set { SetProperty(ref m_ChildControlWidth, value); } } [SerializeField] protected bool m_ChildControlHeight = true; public bool childControlHeight { get { return m_ChildControlHeight; } set { SetProperty(ref m_ChildControlHeight, value); } } // 根据子节点计算得到自身的min, preferred, flexible protected void CalcAlongAxis(int axis, bool isVertical) { float combinedPadding = (axis == 0 ? padding.horizontal : padding.vertical); // padding是left+right, top+bottom bool controlSize = (axis == 0 ? m_ChildControlWidth : m_ChildControlHeight); bool childForceExpandSize = (axis == 0 ? childForceExpandWidth : childForceExpandHeight); float totalMin = combinedPadding; // 所有子节点的min之和 float totalPreferred = combinedPadding; // 所有子节点的preferred之和 float totalFlexible = 0; // 是一个无单位数值,等于所有子节点的flexible值相加 bool alongOtherAxis = (isVertical ^ (axis == 1)); for (int i = 0; i < rectChildren.Count; i++) { RectTransform child = rectChildren[i]; float min, preferred, flexible; // 子节点的三个属性值 GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); if (alongOtherAxis) { totalMin = Mathf.Max(min + combinedPadding, totalMin); totalPreferred = Mathf.Max(preferred + combinedPadding, totalPreferred); totalFlexible = Mathf.Max(flexible, totalFlexible); } else { totalMin += min + spacing; totalPreferred += preferred + spacing; // Increment flexible size with element's flexible size. totalFlexible += flexible; } } // 减去最后一个子节点多加的spacing if (!alongOtherAxis && rectChildren.Count > 0) { totalMin -= spacing; totalPreferred -= spacing; } totalPreferred = Mathf.Max(totalMin, totalPreferred); // 保存到m_TotalMinSize, m_TotalPreferredSize, m_TotalFlexibleSize SetLayoutInputForAxis(totalMin, totalPreferred, totalFlexible, axis); } protected void SetChildrenAlongAxis(int axis, bool isVertical) { float size = rectTransform.rect.size[axis]; // RectTransform大小 bool controlSize = (axis == 0 ? m_ChildControlWidth : m_ChildControlHeight); bool childForceExpandSize = (axis == 0 ? childForceExpandWidth : childForceExpandHeight); float alignmentOnAxis = GetAlignmentOnAxis(axis); bool alongOtherAxis = (isVertical ^ (axis == 1)); if (alongOtherAxis) { float innerSize = size - (axis == 0 ? padding.horizontal : padding.vertical); // 容纳子节点的空间 for (int i = 0; i < rectChildren.Count; i++) { RectTransform child = rectChildren[i]; float min, preferred, flexible; GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); float requiredSpace = Mathf.Clamp(innerSize, min, flexible > 0 ? size : preferred); float startOffset = GetStartOffset(axis, requiredSpace); if (controlSize) { SetChildAlongAxis(child, axis, startOffset, requiredSpace); } else { float offsetInCell = (requiredSpace - child.sizeDelta[axis]) * alignmentOnAxis; SetChildAlongAxis(child, axis, startOffset + offsetInCell); } } } else { float pos = (axis == 0 ? padding.left : padding.top); if (GetTotalFlexibleSize(axis) == 0 && GetTotalPreferredSize(axis) < size) pos = GetStartOffset(axis, GetTotalPreferredSize(axis) - (axis == 0 ? padding.horizontal : padding.vertical)); float minMaxLerp = 0; // 塞进min之后的剩余空间/preferred-min的空间,是子节点从min向preferred扩大的依据 if (GetTotalMinSize(axis) != GetTotalPreferredSize(axis)) minMaxLerp = Mathf.Clamp01((size - GetTotalMinSize(axis)) / (GetTotalPreferredSize(axis) - GetTotalMinSize(axis))); float itemFlexibleMultiplier = 0; // 塞进preferred之后,进一步塞满剩余空间的依据,即flexible if (size > GetTotalPreferredSize(axis)) { if (GetTotalFlexibleSize(axis) > 0) itemFlexibleMultiplier = (size - GetTotalPreferredSize(axis)) / GetTotalFlexibleSize(axis); } for (int i = 0; i < rectChildren.Count; i++) { RectTransform child = rectChildren[i]; float min, preferred, flexible; GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); float childSize = Mathf.Lerp(min, preferred, minMaxLerp); childSize += flexible * itemFlexibleMultiplier; if (controlSize) { // 设置子节点的transform SetChildAlongAxis(child, axis, pos, childSize); } else { float offsetInCell = (childSize - child.sizeDelta[axis]) * alignmentOnAxis; SetChildAlongAxis(child, axis, pos + offsetInCell); } pos += childSize + spacing; } } } // 返回节点的min, prefered, flexible大小 // axis 0是x轴,1是y轴 // controlSize 是否勾选ChildControlSize // childForceExpand 是否勾选ChildForceExpand private void GetChildSizes(RectTransform child, int axis, bool controlSize, bool childForceExpand, out float min, out float preferred, out float flexible) { if (!controlSize) // 如果没勾ChildControlSize,那么会忽略 { min = child.sizeDelta[axis];//sizeDelta这里等价于size,因为动态布局系统里面anchor都是一起的 preferred = min; flexible = 0; } else { min = LayoutUtility.GetMinSize(child, axis); preferred = LayoutUtility.GetPreferredSize(child, axis); flexible = LayoutUtility.GetFlexibleSize(child, axis); } if (childForceExpand) flexible = Mathf.Max(flexible, 1); } #if UNITY_EDITOR protected override void Reset() { base.Reset(); // For new added components we want these to be set to false, // so that the user's sizes won't be overwritten before they // have a chance to turn these settings off. // However, for existing components that were added before this // feature was introduced, we want it to be on be default for // backwardds compatibility. // Hence their default value is on, but we set to off in reset. m_ChildControlWidth = false; m_ChildControlHeight = false; } #endif } }