Tanoda
TableLayoutGroup.cs
Go to the documentation of this file.
1
3
5{
9 [AddComponentMenu("Layout/Extensions/Table Layout Group")]
10 public class TableLayoutGroup : LayoutGroup
11 {
12 public enum Corner
13 {
14 UpperLeft = 0,
15 UpperRight = 1,
16 LowerLeft = 2,
17 LowerRight = 3
18 }
19
20 [SerializeField]
21 protected Corner startCorner = Corner.UpperLeft;
26 {
27 get { return startCorner; }
28 set
29 {
30 SetProperty(ref startCorner, value);
31 }
32 }
33
34 [SerializeField]
35 protected float[] columnWidths = new float[1] { 96f };
39 public float[] ColumnWidths
40 {
41 get { return columnWidths; }
42 set
43 {
44 SetProperty(ref columnWidths, value);
45 }
46 }
47
48 [SerializeField]
49 protected float minimumRowHeight = 32f;
53 public float MinimumRowHeight
54 {
55 get { return minimumRowHeight; }
56 set
57 {
58 SetProperty(ref minimumRowHeight, value);
59 }
60 }
61
62 [SerializeField]
63 protected bool flexibleRowHeight = true;
68 {
69 get { return flexibleRowHeight; }
70 set
71 {
72 SetProperty(ref flexibleRowHeight, value);
73 }
74 }
75
76 [SerializeField]
77 protected float columnSpacing = 0f;
81 public float ColumnSpacing
82 {
83 get { return columnSpacing; }
84 set
85 {
86 SetProperty(ref columnSpacing, value);
87 }
88 }
89
90 [SerializeField]
91 protected float rowSpacing = 0;
95 public float RowSpacing
96 {
97 get { return rowSpacing; }
98 set
99 {
100 SetProperty(ref rowSpacing, value);
101 }
102 }
103
104 // Temporarily stores data generated during the execution CalculateLayoutInputVertical for use in SetLayoutVertical
105 private float[] preferredRowHeights;
106
107 public override void CalculateLayoutInputHorizontal()
108 {
109 base.CalculateLayoutInputHorizontal();
110
111 float horizontalSize = padding.horizontal;
112
113 // We calculate the actual cell count for cases where the number of children is lesser than the number of columns
114 int actualCellCount = Mathf.Min(rectChildren.Count, columnWidths.Length);
115
116 for (int i = 0; i < actualCellCount; i++)
117 {
118 horizontalSize += columnWidths[i];
119 horizontalSize += columnSpacing;
120 }
121
122 horizontalSize -= columnSpacing;
123
124 SetLayoutInputForAxis(horizontalSize, horizontalSize, 0, 0);
125 }
126
127 public override void CalculateLayoutInputVertical()
128 {
129 int columnCount = columnWidths.Length;
130 int rowCount = Mathf.CeilToInt(rectChildren.Count / (float)columnCount);
131
132 preferredRowHeights = new float[rowCount];
133
134 float totalMinHeight = padding.vertical;
135 float totalPreferredHeight = padding.vertical;
136
137 if (rowCount > 1)
138 {
139 float heightFromSpacing = ((rowCount - 1) * rowSpacing);
140 totalMinHeight += heightFromSpacing;
141 totalPreferredHeight += heightFromSpacing;
142 }
143
145 {
146 // If flexibleRowHeight is enabled, find the max value for minimum and preferred heights in each row
147
148 float maxMinimumHeightInRow = 0;
149 float maxPreferredHeightInRow = 0;
150
151 for (int i = 0; i < rowCount; i++)
152 {
153 maxMinimumHeightInRow = minimumRowHeight;
154 maxPreferredHeightInRow = minimumRowHeight;
155
156 for (int j = 0; j < columnCount; j++)
157 {
158 int childIndex = (i * columnCount) + j;
159
160 // Safeguard against tables with incomplete rows
161 if (childIndex == rectChildren.Count)
162 break;
163
164 maxPreferredHeightInRow = Mathf.Max(LayoutUtility.GetPreferredHeight(rectChildren[childIndex]), maxPreferredHeightInRow);
165 maxMinimumHeightInRow = Mathf.Max(LayoutUtility.GetMinHeight(rectChildren[childIndex]), maxMinimumHeightInRow);
166 }
167
168 totalMinHeight += maxMinimumHeightInRow;
169 totalPreferredHeight += maxPreferredHeightInRow;
170
171 // Add calculated row height to a commonly accessible array for reuse in SetLayoutVertical()
172 preferredRowHeights[i] = maxPreferredHeightInRow;
173 }
174 }
175 else
176 {
177 // If flexibleRowHeight is disabled, then use the minimumRowHeight to calculate vertical layout information
178 for (int i = 0; i < rowCount; i++)
179 preferredRowHeights[i] = minimumRowHeight;
180
181 totalMinHeight += rowCount * minimumRowHeight;
182 totalPreferredHeight = totalMinHeight;
183 }
184
185 totalPreferredHeight = Mathf.Max(totalMinHeight, totalPreferredHeight);
186 SetLayoutInputForAxis(totalMinHeight, totalPreferredHeight, 1, 1);
187 }
188
189 public override void SetLayoutHorizontal()
190 {
191 // If no column width is defined, then assign a reasonable default
192 if (columnWidths.Length == 0)
193 columnWidths = new float[1] { 0f };
194
195 int columnCount = columnWidths.Length;
196 int cornerX = (int)startCorner % 2;
197
198 float startOffset = 0;
199 float requiredSizeWithoutPadding = 0;
200
201 // We calculate the actual cell count for cases where the number of children is lesser than the number of columns
202 int actualCellCount = Mathf.Min(rectChildren.Count, columnWidths.Length);
203
204 for (int i = 0; i < actualCellCount; i++)
205 {
206 requiredSizeWithoutPadding += columnWidths[i];
207 requiredSizeWithoutPadding += columnSpacing;
208 }
209
210 requiredSizeWithoutPadding -= columnSpacing;
211
212 startOffset = GetStartOffset(0, requiredSizeWithoutPadding);
213
214 if (cornerX == 1)
215 startOffset += requiredSizeWithoutPadding;
216
217 float positionX = startOffset;
218
219 for (int i = 0; i < rectChildren.Count; i++)
220 {
221 int currentColumnIndex = i % columnCount;
222
223 // If it's the first cell in the row, reset positionX
224 if (currentColumnIndex == 0)
225 positionX = startOffset;
226
227 if (cornerX == 1)
228 positionX -= columnWidths[currentColumnIndex];
229
230 SetChildAlongAxis(rectChildren[i], 0, positionX, columnWidths[currentColumnIndex]);
231
232 if (cornerX == 1)
233 positionX -= columnSpacing;
234 else
235 positionX += columnWidths[currentColumnIndex] + columnSpacing;
236 }
237 }
238
239 public override void SetLayoutVertical()
240 {
241 int columnCount = columnWidths.Length;
242 int rowCount = preferredRowHeights.Length;
243
244 int cornerY = (int)startCorner / 2;
245
246 float startOffset = 0;
247 float requiredSizeWithoutPadding = 0;
248
249 for (int i = 0; i < rowCount; i++)
250 requiredSizeWithoutPadding += preferredRowHeights[i];
251
252 if (rowCount > 1)
253 requiredSizeWithoutPadding += (rowCount - 1) * rowSpacing;
254
255 startOffset = GetStartOffset(1, requiredSizeWithoutPadding);
256
257 if (cornerY == 1)
258 startOffset += requiredSizeWithoutPadding;
259
260 float positionY = startOffset;
261
262 for (int i = 0; i < rowCount; i++)
263 {
264 if (cornerY == 1)
265 positionY -= preferredRowHeights[i];
266
267 for (int j = 0; j < columnCount; j++)
268 {
269 int childIndex = (i * columnCount) + j;
270
271 // Safeguard against tables with incomplete rows
272 if (childIndex == rectChildren.Count)
273 break;
274
275 SetChildAlongAxis(rectChildren[childIndex], 1, positionY, preferredRowHeights[i]);
276 }
277
278 if (cornerY == 1)
279 positionY -= rowSpacing;
280 else
281 positionY += preferredRowHeights[i] + rowSpacing;
282 }
283
284 // Set preferredRowHeights to null to free memory
285 preferredRowHeights = null;
286 }
287 }
288}
Arranges child objects into a non-uniform grid, with fixed column widths and flexible row heights
Corner StartCorner
The corner starting from which the cells should be arranged
float ColumnSpacing
The horizontal spacing between each cell in the table
float[] ColumnWidths
The widths of all the columns in the table
float MinimumRowHeight
The minimum height for any row in the table
bool FlexibleRowHeight
Expand rows to fit the cell with the highest preferred height?
float RowSpacing
The vertical spacing between each row in the table
Credit Erdener Gonenc - @PixelEnvision.