GridLayoutGroup:继承自LayoutGroup,为网格布局组件,它同时实现了水平和竖直布局。
源码解析
枚举Corner:标记网格起始的位置,有左上角、右上角、左下角、右下角。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public enum Corner { UpperLeft = 0, UpperRight = 1, LowerLeft = 2, LowerRight = 3 }
|
Axis:标记开始排列的轴方向,有水平轴和垂直轴。
1 2 3 4 5 6 7 8 9 10 11
| public enum Axis { Horizontal = 0, Vertical = 1 }
|
Constraint:约束行列的个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public enum Constraint { Flexible = 0, FixedColumnCount = 1, FixedRowCount = 2 }
|
一些序列化的字段
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
|
[SerializeField] protected Corner m_StartCorner = Corner.UpperLeft; public Corner startCorner { get { return m_StartCorner; } set { SetProperty(ref m_StartCorner, value); } }
[SerializeField] protected Axis m_StartAxis = Axis.Horizontal; public Axis startAxis { get { return m_StartAxis; } set { SetProperty(ref m_StartAxis, value); } }
[SerializeField] protected Vector2 m_CellSize = new Vector2(100, 100); public Vector2 cellSize { get { return m_CellSize; } set { SetProperty(ref m_CellSize, value); } }
[SerializeField] protected Vector2 m_Spacing = Vector2.zero; public Vector2 spacing { get { return m_Spacing; } set { SetProperty(ref m_Spacing, value); } }
[SerializeField] protected Constraint m_Constraint = Constraint.Flexible; public Constraint constraint { get { return m_Constraint; } set { SetProperty(ref m_Constraint, value); } }
[SerializeField] protected int m_ConstraintCount = 2; public int constraintCount { get { return m_ConstraintCount; } set { SetProperty(ref m_ConstraintCount, Mathf.Max(1, value)); } }
|
OnValidate:强制刷新 constraintCount 确保它的值在编辑器中能被正确应用和验证。
1 2 3 4 5 6 7
| #if UNITY_EDITOR protected override void OnValidate() { base.OnValidate(); constraintCount = constraintCount; } #endif
|
UGUI源码解析——LayoutGroup
CalculateLayoutInputHorizontal:由布局系统调用,计算水平布局的大小。
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
| public override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal();
int minColumns = 0; int preferredColumns = 0; if (m_Constraint == Constraint.FixedColumnCount) { minColumns = preferredColumns = m_ConstraintCount; } else if (m_Constraint == Constraint.FixedRowCount) { minColumns = preferredColumns = Mathf.CeilToInt(rectChildren.Count / (float)m_ConstraintCount - 0.001f); } else { minColumns = 1; preferredColumns = Mathf.CeilToInt(Mathf.Sqrt(rectChildren.Count)); }
SetLayoutInputForAxis( padding.horizontal + (cellSize.x + spacing.x) * minColumns - spacing.x, padding.horizontal + (cellSize.x + spacing.x) * preferredColumns - spacing.x, -1, 0); }
|
CalculateLayoutInputVertical:由布局系统调用,计算垂直布局的大小。
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
| public override void CalculateLayoutInputVertical() { int minRows = 0; if (m_Constraint == Constraint.FixedColumnCount) { minRows = Mathf.CeilToInt(rectChildren.Count / (float)m_ConstraintCount - 0.001f); } else if (m_Constraint == Constraint.FixedRowCount) { minRows = m_ConstraintCount; } else { float width = rectTransform.rect.width; int cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - padding.horizontal + spacing.x + 0.001f) / (cellSize.x + spacing.x))); minRows = Mathf.CeilToInt(rectChildren.Count / (float)cellCountX); } float minSpace = padding.vertical + (cellSize.y + spacing.y) * minRows - spacing.y; SetLayoutInputForAxis(minSpace, minSpace, -1, 1); }
|
SetLayoutVertical:这个方法通常用于在水平方向上设置布局,以确保布局组件内的子对象按照规定的方式进行排列和调整位置。
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
| public override void SetLayoutVertical() { SetCellsAlongAxis(1); }
private void SetCellsAlongAxis(int axis) { if (axis == 0) { for (int i = 0; i < rectChildren.Count; i++) { RectTransform rect = rectChildren[i];
m_Tracker.Add(this, rect, DrivenTransformProperties.Anchors | DrivenTransformProperties.AnchoredPosition | DrivenTransformProperties.SizeDelta);
rect.anchorMin = Vector2.up; rect.anchorMax = Vector2.up; rect.sizeDelta = cellSize; } return; }
float width = rectTransform.rect.size.x; float height = rectTransform.rect.size.y;
int cellCountX = 1; int cellCountY = 1; if (m_Constraint == Constraint.FixedColumnCount) { cellCountX = m_ConstraintCount;
if (rectChildren.Count > cellCountX) cellCountY = rectChildren.Count / cellCountX + (rectChildren.Count % cellCountX > 0 ? 1 : 0); } else if (m_Constraint == Constraint.FixedRowCount) { cellCountY = m_ConstraintCount;
if (rectChildren.Count > cellCountY) cellCountX = rectChildren.Count / cellCountY + (rectChildren.Count % cellCountY > 0 ? 1 : 0); } else { if (cellSize.x + spacing.x <= 0) cellCountX = int.MaxValue; else cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - padding.horizontal + spacing.x + 0.001f) / (cellSize.x + spacing.x)));
if (cellSize.y + spacing.y <= 0) cellCountY = int.MaxValue; else cellCountY = Mathf.Max(1, Mathf.FloorToInt((height - padding.vertical + spacing.y + 0.001f) / (cellSize.y + spacing.y))); }
int cornerX = (int)startCorner % 2; int cornerY = (int)startCorner / 2;
int cellsPerMainAxis, actualCellCountX, actualCellCountY; if (startAxis == Axis.Horizontal) { cellsPerMainAxis = cellCountX; actualCellCountX = Mathf.Clamp(cellCountX, 1, rectChildren.Count); actualCellCountY = Mathf.Clamp(cellCountY, 1, Mathf.CeilToInt(rectChildren.Count / (float)cellsPerMainAxis)); } else { cellsPerMainAxis = cellCountY; actualCellCountY = Mathf.Clamp(cellCountY, 1, rectChildren.Count); actualCellCountX = Mathf.Clamp(cellCountX, 1, Mathf.CeilToInt(rectChildren.Count / (float)cellsPerMainAxis)); }
Vector2 requiredSpace = new Vector2( actualCellCountX * cellSize.x + (actualCellCountX - 1) * spacing.x, actualCellCountY * cellSize.y + (actualCellCountY - 1) * spacing.y ); Vector2 startOffset = new Vector2( GetStartOffset(0, requiredSpace.x), GetStartOffset(1, requiredSpace.y) );
for (int i = 0; i < rectChildren.Count; i++) { int positionX; int positionY; if (startAxis == Axis.Horizontal) { positionX = i % cellsPerMainAxis; positionY = i / cellsPerMainAxis; } else { positionX = i / cellsPerMainAxis; positionY = i % cellsPerMainAxis; } if (cornerX == 1) positionX = actualCellCountX - 1 - positionX; if (cornerY == 1) positionY = actualCellCountY - 1 - positionY;
SetChildAlongAxis(rectChildren[i], 0, startOffset.x + (cellSize[0] + spacing[0]) * positionX, cellSize[0]); SetChildAlongAxis(rectChildren[i], 1, startOffset.y + (cellSize[1] + spacing[1]) * positionY, cellSize[1]); } }
|
UGUI源码解析——GridLayoutGroup