From b350b270f733db5029e75bc4567d7eca2956989d Mon Sep 17 00:00:00 2001 From: Rahul Raman Date: Tue, 27 Dec 2016 19:51:46 +0000 Subject: [PATCH] Added TableLayout component that child objects into a non-uniform grid, with fixed, user-defined column widths and flexible row heights --HG-- branch : develop_5.3 --- Scripts/Layout/TableLayout.cs | 271 ++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 Scripts/Layout/TableLayout.cs diff --git a/Scripts/Layout/TableLayout.cs b/Scripts/Layout/TableLayout.cs new file mode 100644 index 0000000..4ee3be7 --- /dev/null +++ b/Scripts/Layout/TableLayout.cs @@ -0,0 +1,271 @@ +/// Credit RahulOfTheRamanEffect +/// Sourced from - https://forum.unity3d.com/members/rahuloftheramaneffect.773241/ + +namespace UnityEngine.UI.Extensions +{ + /// + /// Arranges child objects into a non-uniform grid, with fixed column widths and flexible row heights + /// + public class TableLayout : LayoutGroup + { + public enum Corner + { + UpperLeft = 0, + UpperRight = 1, + LowerLeft = 2, + LowerRight = 3 + } + + [SerializeField] + protected Corner startCorner = Corner.UpperLeft; + /// + /// The corner starting from which the cells should be arranged + /// + public Corner StartCorner + { + get { return startCorner; } + set + { + SetProperty(ref startCorner, value); + } + } + + [SerializeField] + protected float[] columnWidths = new float[0]; + /// + /// The widths of all the columns in the table + /// + public float[] ColumnWidths + { + get { return columnWidths; } + set + { + SetProperty(ref columnWidths, value); + } + } + + [SerializeField] + protected float minimumRowHeight = 32f; + /// + /// The minimum height for any row in the table + /// + public float MinimumRowHeight + { + get { return minimumRowHeight; } + set + { + SetProperty(ref minimumRowHeight, value); + } + } + + [SerializeField] + protected float cellSpacing = 0f; + /// + /// The horizontal spacing between each cell in the table + /// + public float CellSpacing + { + get { return cellSpacing; } + set + { + SetProperty(ref cellSpacing, value); + } + } + + [SerializeField] + protected float rowSpacing = 0; + /// + /// The vertical spacing between each row in the table + /// + public float RowSpacing + { + get { return rowSpacing; } + set + { + SetProperty(ref rowSpacing, value); + } + } + + public override void CalculateLayoutInputHorizontal() + { + base.CalculateLayoutInputHorizontal(); + + float horizontalSize = padding.horizontal; + + if (columnWidths.Length > 1) + horizontalSize += ((columnWidths.Length - 1) * cellSpacing); + + // We calculate the actual cell count for cases where the number of children is lesser than the number of columns + int actualCellCount = Mathf.Min(rectChildren.Count, columnWidths.Length); + + for (int i = 0; i < actualCellCount; i++) + horizontalSize += columnWidths[i]; + + SetLayoutInputForAxis(horizontalSize, horizontalSize, 0, 0); + } + + public override void CalculateLayoutInputVertical() + { + int rowCount = Mathf.CeilToInt(rectChildren.Count / (float)columnWidths.Length); + + float totalMinHeight = padding.vertical; + float totalPreferredHeight = padding.vertical; + + if (rowCount > 1) + { + float heightFromSpacing = ((rowCount - 1) * rowSpacing); + totalMinHeight += heightFromSpacing; + totalPreferredHeight += heightFromSpacing; + } + + // Find the max value for minimum and preferred heights in each row + for (int i = 0; i < rowCount; i++) + { + float maxMinimumHeightInRow = 0; + float maxPreferredHeightInRow = 0; + + for (int j = 0; j < columnWidths.Length; j++) + { + int childIndex = (i * columnWidths.Length) + j; + + if (childIndex >= rectChildren.Count) + break; + + maxPreferredHeightInRow = Mathf.Max(LayoutUtility.GetPreferredHeight(rectChildren[childIndex]), maxPreferredHeightInRow); + maxMinimumHeightInRow = Mathf.Max(LayoutUtility.GetMinHeight(rectChildren[childIndex]), maxMinimumHeightInRow); + } + + maxMinimumHeightInRow = Mathf.Max(minimumRowHeight, maxMinimumHeightInRow); + totalMinHeight += maxMinimumHeightInRow; + + maxPreferredHeightInRow = Mathf.Max(minimumRowHeight, maxPreferredHeightInRow); + totalPreferredHeight += maxPreferredHeightInRow; + } + + + totalPreferredHeight = Mathf.Max(totalMinHeight, totalPreferredHeight); + SetLayoutInputForAxis(totalMinHeight, totalPreferredHeight, 1, 1); + } + + public override void SetLayoutHorizontal() + { + int columnCount = columnWidths.Length; + + for (int i = 0; i < rectChildren.Count; i++) + { + RectTransform child = rectChildren[i]; + m_Tracker.Add(this, child, + DrivenTransformProperties.Anchors | + DrivenTransformProperties.AnchoredPosition | + DrivenTransformProperties.SizeDelta); + child.anchorMin = Vector2.up; + child.anchorMax = Vector2.up; + Vector2 childSizeDelta = child.sizeDelta; + childSizeDelta.x = columnWidths[i % columnCount]; + child.sizeDelta = childSizeDelta; + } + } + + public override void SetLayoutVertical() + { + float tableLayoutHeight = rectTransform.rect.height; + + int columnCount = columnWidths.Length; + int rowCount = Mathf.CeilToInt(rectChildren.Count / (float)columnCount); + + int cornerX = (int)startCorner % 2; + int cornerY = (int)startCorner / 2; + + Vector2 startOffset = new Vector2(); + + float requiredWidthWithoutPadding = 0; + for (int i = 0; i < columnWidths.Length; i++) + { + requiredWidthWithoutPadding += columnWidths[i]; + requiredWidthWithoutPadding += cellSpacing; + } + requiredWidthWithoutPadding -= cellSpacing; + + startOffset.x = GetStartOffset(0, requiredWidthWithoutPadding); + + float requiredHeightWithoutPadding = 0; + + for (int i = 0; i < rowCount; i++) + { + float maxPreferredHeightInRow = 0; + + for (int j = 0; j < columnCount; j++) + { + int childIndex = (i * columnCount) + j; + + if (childIndex >= rectChildren.Count) + break; + + maxPreferredHeightInRow = Mathf.Max(LayoutUtility.GetPreferredHeight(rectChildren[childIndex]), maxPreferredHeightInRow); + } + + maxPreferredHeightInRow = Mathf.Max(minimumRowHeight, maxPreferredHeightInRow); + requiredHeightWithoutPadding += maxPreferredHeightInRow; + requiredHeightWithoutPadding += rowSpacing; + } + + requiredHeightWithoutPadding -= rowSpacing; + + startOffset.y = GetStartOffset(1, requiredHeightWithoutPadding); + + if (cornerX == 1) + startOffset.x += requiredWidthWithoutPadding; + + if (cornerY == 1) + startOffset.y += requiredHeightWithoutPadding; + + float positionY = startOffset.y; + + for (int i = 0; i < rowCount; i++) + { + float positionX = startOffset.x; + + float maxPreferredHeightInRow = 0; + + for (int j = 0; j < columnCount; j++) + { + int childIndex = (i * columnCount) + j; + + if (childIndex >= rectChildren.Count) + break; + + float sizeXOfRect = columnWidths[j] + cellSpacing; + + if (cornerX == 1) + positionX -= sizeXOfRect; + + SetChildAlongAxis(rectChildren[childIndex], 0, positionX, columnWidths[j]); + + if (cornerX != 1) + positionX += sizeXOfRect; + + maxPreferredHeightInRow = Mathf.Max(LayoutUtility.GetPreferredHeight(rectChildren[childIndex]), maxPreferredHeightInRow); + } + + maxPreferredHeightInRow = Mathf.Max(minimumRowHeight, maxPreferredHeightInRow); + float sizeYOfRect = maxPreferredHeightInRow + rowSpacing; + + if (cornerY == 1) + positionY -= sizeYOfRect; + + for (int j = 0; j < columnCount; j++) + { + int childIndex = (i * columnCount) + j; + + if (childIndex >= rectChildren.Count) + break; + + SetChildAlongAxis(rectChildren[childIndex], 1, positionY, maxPreferredHeightInRow); + } + + if (cornerY != 1) + positionY += sizeYOfRect; + } + } + } +} \ No newline at end of file