1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
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
}
}
|