Advertisement
HashZayed

AutoExpandGridLayoutGroup

Oct 16th, 2017
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.63 KB | None | 0 0
  1. /// <summary>
  2. /// AutoExpandGridLayoutGroup a variation of Unity's Grid Layout Group.
  3. /// It sorts children under a panel into dynamic grid layout.
  4. /// Also resizes children inside panel according to panel size and child count.
  5. /// Helps taken from https://forum.unity.com/threads/solved-how-to-make-grid-layout-group-cell-size-x-auto-expand.448534/
  6. /// </summary>
  7. using UnityEngine;
  8. using System.Collections.Generic;
  9.  
  10. namespace UnityEngine.UI
  11. {
  12.     [AddComponentMenu("Layout/Auto Expand Grid Layout Group", 152)]
  13.     public class AutoExpandGridLayoutGroup : LayoutGroup
  14.     {
  15.         public enum Corner { UpperLeft = 0, UpperRight = 1, LowerLeft = 2, LowerRight = 3 }
  16.         public enum Axis { Horizontal = 0, Vertical = 1 }
  17.         public enum Constraint { Flexible = 0, FixedColumnCount = 1, FixedRowCount = 2 }
  18.  
  19.         [SerializeField]
  20.         protected Corner m_StartCorner = Corner.UpperLeft;
  21.         public Corner startCorner { get { return m_StartCorner; } set { SetProperty(ref m_StartCorner, value); } }
  22.  
  23.         [SerializeField]
  24.         protected Axis m_StartAxis = Axis.Horizontal;
  25.         public Axis startAxis { get { return m_StartAxis; } set { SetProperty(ref m_StartAxis, value); } }
  26.  
  27.         [SerializeField]
  28.         protected Vector2 m_CellSize = new Vector2(100, 100);
  29.         public Vector2 cellSize { get { return m_CellSize; } set { SetProperty(ref m_CellSize, value); } }
  30.  
  31.         [SerializeField]
  32.         protected Vector2 m_Spacing = Vector2.zero;
  33.         public Vector2 spacing { get { return m_Spacing; } set { SetProperty(ref m_Spacing, value); } }
  34.  
  35.         [SerializeField]
  36.         protected Constraint m_Constraint = Constraint.Flexible;
  37.         public Constraint constraint { get { return m_Constraint; } set { SetProperty(ref m_Constraint, value); } }
  38.  
  39.         [SerializeField]
  40.         protected int m_ConstraintCount = 2;
  41.         public int constraintCount { get { return m_ConstraintCount; } set { SetProperty(ref m_ConstraintCount, Mathf.Max(1, value)); } }
  42.  
  43.         protected AutoExpandGridLayoutGroup()
  44.         { }
  45.  
  46.         #if UNITY_EDITOR
  47.         protected override void OnValidate()
  48.         {
  49.             base.OnValidate();
  50.             constraintCount = constraintCount;
  51.         }
  52.         #endif
  53.  
  54.         protected override void OnRectTransformDimensionsChange(){
  55.             base.OnRectTransformDimensionsChange ();
  56.             float meSize = getPieceSquareCalculated (rectTransform.rect.size.y, rectTransform.rect.size.x, rectChildren.Count);
  57.             m_CellSize = new Vector2 (meSize,meSize);
  58.         }
  59.         protected virtual void OnTransformChildrenChanged(){
  60.             base.OnTransformChildrenChanged();
  61.             float meSize = getPieceSquareCalculated (rectTransform.rect.size.y, rectTransform.rect.size.x, rectChildren.Count);
  62.             m_CellSize = new Vector2 (meSize,meSize);
  63.         }
  64.         public override void CalculateLayoutInputHorizontal()
  65.         {
  66.             base.CalculateLayoutInputHorizontal();
  67.  
  68.             int minColumns = 0;
  69.             int preferredColumns = 0;
  70.             if (m_Constraint == Constraint.FixedColumnCount)
  71.             {
  72.                 minColumns = preferredColumns = m_ConstraintCount;
  73.             }
  74.             else if (m_Constraint == Constraint.FixedRowCount)
  75.             {
  76.                 minColumns = preferredColumns = Mathf.CeilToInt(rectChildren.Count / (float)m_ConstraintCount - 0.001f);
  77.             }
  78.             else
  79.             {
  80.                 minColumns = 1;
  81.                 preferredColumns = Mathf.CeilToInt(Mathf.Sqrt(rectChildren.Count));
  82.             }
  83.  
  84.             SetLayoutInputForAxis(
  85.                 padding.horizontal + (cellSize.x + spacing.x) * minColumns - spacing.x,
  86.                 padding.horizontal + (cellSize.x + spacing.x) * preferredColumns - spacing.x,
  87.                 -1, 0);
  88.         }
  89.  
  90.         public override void CalculateLayoutInputVertical()
  91.         {
  92.             int minRows = 0;
  93.             if (m_Constraint == Constraint.FixedColumnCount)
  94.             {
  95.                 minRows = Mathf.CeilToInt(rectChildren.Count / (float)m_ConstraintCount - 0.001f);
  96.             }
  97.             else if (m_Constraint == Constraint.FixedRowCount)
  98.             {
  99.                 minRows = m_ConstraintCount;
  100.             }
  101.             else
  102.             {
  103.                 float width = rectTransform.rect.size.x;
  104.                 int cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - padding.horizontal + spacing.x + 0.001f) / (cellSize.x + spacing.x)));
  105.                 minRows = Mathf.CeilToInt(rectChildren.Count / (float)cellCountX);
  106.             }
  107.  
  108.             float minSpace = padding.vertical + (cellSize.y + spacing.y) * minRows - spacing.y;
  109.             SetLayoutInputForAxis(minSpace, minSpace, -1, 1);
  110.         }
  111.  
  112.         public override void SetLayoutHorizontal()
  113.         {
  114.             SetCellsAlongAxis(0);
  115.         }
  116.  
  117.         public override void SetLayoutVertical()
  118.         {
  119.             SetCellsAlongAxis(1);
  120.         }
  121.  
  122.         private void SetCellsAlongAxis(int axis)
  123.         {
  124.             // Normally a Layout Controller should only set horizontal values when invoked for the horizontal axis
  125.             // and only vertical values when invoked for the vertical axis.
  126.             // However, in this case we set both the horizontal and vertical position when invoked for the vertical axis.
  127.             // Since we only set the horizontal position and not the size, it shouldn't affect children's layout,
  128.             // and thus shouldn't break the rule that all horizontal layout must be calculated before all vertical layout.
  129.  
  130.             if (axis == 0)
  131.             {
  132.                 // Only set the sizes when invoked for horizontal axis, not the positions.
  133.                 for (int i = 0; i < rectChildren.Count; i++)
  134.                 {
  135.                     RectTransform rect = rectChildren[i];
  136.  
  137.                     m_Tracker.Add(this, rect,
  138.                         DrivenTransformProperties.Anchors |
  139.                         DrivenTransformProperties.AnchoredPosition |
  140.                         DrivenTransformProperties.SizeDelta);
  141.  
  142.                     rect.anchorMin = Vector2.up;
  143.                     rect.anchorMax = Vector2.up;
  144.                     rect.sizeDelta = cellSize;
  145.                 }
  146.                 return;
  147.             }
  148.  
  149.             float width = rectTransform.rect.size.x;
  150.             float height = rectTransform.rect.size.y;
  151.  
  152.             int cellCountX = 1;
  153.             int cellCountY = 1;
  154.             if (m_Constraint == Constraint.FixedColumnCount)
  155.             {
  156.                 cellCountX = m_ConstraintCount;
  157.                 cellCountY = Mathf.CeilToInt(rectChildren.Count / (float)cellCountX - 0.001f);
  158.             }
  159.             else if (m_Constraint == Constraint.FixedRowCount)
  160.             {
  161.                 cellCountY = m_ConstraintCount;
  162.                 cellCountX = Mathf.CeilToInt(rectChildren.Count / (float)cellCountY - 0.001f);
  163.             }
  164.             else
  165.             {
  166.                 if (cellSize.x + spacing.x <= 0)
  167.                     cellCountX = int.MaxValue;
  168.                 else
  169.                     cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - padding.horizontal + spacing.x + 0.001f) / (cellSize.x + spacing.x)));
  170.  
  171.                 if (cellSize.y + spacing.y <= 0)
  172.                     cellCountY = int.MaxValue;
  173.                 else
  174.                     cellCountY = Mathf.Max(1, Mathf.FloorToInt((height - padding.vertical + spacing.y + 0.001f) / (cellSize.y + spacing.y)));
  175.             }
  176.  
  177.             int cornerX = (int)startCorner % 2;
  178.             int cornerY = (int)startCorner / 2;
  179.  
  180.             int cellsPerMainAxis, actualCellCountX, actualCellCountY;
  181.             if (startAxis == Axis.Horizontal)
  182.             {
  183.                 cellsPerMainAxis = cellCountX;
  184.                 actualCellCountX = Mathf.Clamp(cellCountX, 1, rectChildren.Count);
  185.                 actualCellCountY = Mathf.Clamp(cellCountY, 1, Mathf.CeilToInt(rectChildren.Count / (float)cellsPerMainAxis));
  186.             }
  187.             else
  188.             {
  189.                 cellsPerMainAxis = cellCountY;
  190.                 actualCellCountY = Mathf.Clamp(cellCountY, 1, rectChildren.Count);
  191.                 actualCellCountX = Mathf.Clamp(cellCountX, 1, Mathf.CeilToInt(rectChildren.Count / (float)cellsPerMainAxis));
  192.             }
  193.  
  194.             Vector2 requiredSpace = new Vector2(
  195.                 actualCellCountX * cellSize.x + (actualCellCountX - 1) * spacing.x,
  196.                 actualCellCountY * cellSize.y + (actualCellCountY - 1) * spacing.y
  197.             );
  198.             Vector2 startOffset = new Vector2(
  199.                 GetStartOffset(0, requiredSpace.x),
  200.                 GetStartOffset(1, requiredSpace.y)
  201.             );
  202.  
  203.             for (int i = 0; i < rectChildren.Count; i++)
  204.             {
  205.                 int positionX;
  206.                 int positionY;
  207.                 if (startAxis == Axis.Horizontal)
  208.                 {
  209.                     positionX = i % cellsPerMainAxis;
  210.                     positionY = i / cellsPerMainAxis;
  211.                 }
  212.                 else
  213.                 {
  214.                     positionX = i / cellsPerMainAxis;
  215.                     positionY = i % cellsPerMainAxis;
  216.                 }
  217.  
  218.                 if (cornerX == 1)
  219.                     positionX = actualCellCountX - 1 - positionX;
  220.                 if (cornerY == 1)
  221.                     positionY = actualCellCountY - 1 - positionY;
  222.  
  223.                 float realsize = ((width - (spacing[0] * (actualCellCountX - 1))) / actualCellCountX);
  224.                 SetChildAlongAxis(rectChildren[i], 0, startOffset.x + (realsize + spacing[0]) * positionX, realsize);
  225.                 SetChildAlongAxis(rectChildren[i], 1, startOffset.y + (cellSize[1] + spacing[1]) * positionY, cellSize[1]);
  226.             }
  227.         }
  228.         public static float getPieceSquareCalculated(float height, float width, int numberOfPieces)
  229.         {
  230.             float px = Mathf.Ceil(Mathf.Sqrt(numberOfPieces * width / height)) +1;
  231.             px = px == 0 ? 1 : px;
  232.             float sx, sy;
  233.             if (Mathf.Floor(px * height / width) * px < numberOfPieces)  
  234.                 sx = height / Mathf.Ceil(px * height / width);
  235.             else
  236.                 sx = width / px;
  237.             float py = Mathf.Ceil(Mathf.Sqrt(numberOfPieces * height / width))+1;
  238.             py = py == 0 ? 1 : py;
  239.             if (Mathf.Floor(py * width / height) * py < numberOfPieces)  
  240.                 sy = width / Mathf.Ceil(width * py / height);
  241.             else
  242.                 sy = height / py;
  243.             return Mathf.Max(sx, sy);
  244.         }  
  245.     }
  246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement