Search Unity

Flexible "grid" layout?

Discussion in 'Unity UI & TextMesh Pro' started by SunnySunshine, Feb 5, 2015.

  1. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    641
    I want a layout controller capable of expanding its height based on its children. Basically like a text area works, but instead of words there would be child elements.

    So when adding elements (of variable width) to this layout controller, it would first try to fill its width before going to a new row.

    Is there currently a way to set this up using the pre-existing components in Unity UI? The horizontal and vertical layout groups don't handle rows or columns, respectively. The grid layout seems to require a fixed size of each cell, which is undesirable.

    Obviously a combination of vertical and horizontal groups can be used, but it would be far neater if there's a way to set up a grid layout capable of having children of flexible width. Otherwise a tree of vertical and horizontal groups would have to be rebuilt when children at the top are removed.
     
    Last edited: Feb 5, 2015
  2. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,612
    Yes, you simply need to use a Content Size fitter which will scale a parent GO around it's children.

    If you also use a Layout group, make sure you un check the "Child Force Expand" option for the direction you want it to shrink

    Hope this helps
     
  3. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    641
    Either I'm misunderstanding you, or you me. How would creating a content size fitter automatically create rows, or columns, for a layout group? As far as I know, grid layout is the only layout creating both columns and rows, but that requires a fixed cell size.
     
  4. Pix10

    Pix10

    Joined:
    Jul 21, 2012
    Posts:
    842
    I think you're (maybe) asking the wrong question; reading between the lines, you want a packed layout equivalent of the grid?

    Content size fitter just does what it says...it doesn't care much how the contents are created or by what.
     
  5. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    641
    Last edited: Feb 5, 2015
  6. Pix10

    Pix10

    Joined:
    Jul 21, 2012
    Posts:
    842
    Yeah easy enough (and easy to say!), but you'll have to write this yourself. The UI is open sourced and the UI components are all standard C# components, so a good starting point would be to extend or do a custom component based on GridLayoutGroup.

    https://bitbucket.org/Unity-Technologies/ui
    UI / UnityEngine.UI / UI / Core / Layout / GridLayoutGroup.cs
     
    SunnySunshine likes this.
  7. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,612
    Right, didn't get that distinction in your query.

    No the current Grid layout won't dynamically change it's row value. (just answered that in another post, second today, v.odd)
    Will see if the community comes up with anything or I'll add one myself to the UI Extensions repo https://bitbucket.org/ddreaper/unity-ui-extensions
     
    sstadelman and SunnySunshine like this.
  8. lkc2015

    lkc2015

    Joined:
    Oct 13, 2015
    Posts:
    2
    The best thing to do here is make a grid layout group as the parent then within that group make horizontal layout groups of elements as shown below

    -Grid Layout Group
    -Horizontal Layout Group
    -Element
    -Element
    -Element
    -Element
    -Horizontal Layout Group
    -Element
    -Element
    -Element
    -Element

    You would need to do the math for when you want want to create new horizontal layout groups within the grid layout group

    Hope this helped
     
    MGGDev and Chefty like this.
  9. jamesburford

    jamesburford

    Joined:
    Nov 5, 2012
    Posts:
    4
    So, it wont resize dynamically. What I did was on Start() get the width of the scrolling area (the parent) and then divide it by the number of columns I wanted then changed the fixed cell size in the Grid Layout Group.

    Here is my code:

    Code (CSharp):
    1.     public float width;
    2.  
    3.     // Use this for initialization
    4.     void Start ()
    5.     {
    6.         width = this.gameObject.GetComponent<RectTransform>().rect.width;
    7.         Vector2 newSize = new Vector2(width / 2, width / 2);
    8.         this.gameObject.GetComponent<GridLayoutGroup>().cellSize = newSize;
    9.     }
    You can also do the same for height. Or put the code in Update() if you want it to resize constantly.

    Hope this helps!
     
    Arkade, mike_unity628 and LeroyKim92 like this.
  10. LeroyKim92

    LeroyKim92

    Joined:
    Jan 15, 2017
    Posts:
    5
    This code is so simple and works perfect!! You saved my time a lot. Thank you!!!!
     
  11. Izzy2000

    Izzy2000

    Joined:
    Dec 18, 2013
    Posts:
    49
    ahh, are you looking to have it work just like kissUI's Flowing Layouts?

    ex:
     
    TopRamenGod and zhuxianzhi like this.
  12. XiongGuiYang

    XiongGuiYang

    Joined:
    Sep 5, 2016
    Posts:
    14
    Layout.gif
     

    Attached Files:

    addray likes this.
  13. Harinezumi

    Harinezumi

    Joined:
    Jan 7, 2013
    Posts:
    46
    levlaj likes this.
  14. Sudarmin-Then

    Sudarmin-Then

    Joined:
    Nov 27, 2014
    Posts:
    20
    Just want to add, if someone has a problem like me, which is trying to maximize the horizontal count first in grid layout group before going down

    Code (CSharp):
    1.  
    2. void Start()
    3.     {
    4.         float width;
    5.         GridLayoutGroup lg;
    6.         lg = GetComponent<GridLayoutGroup>();
    7.         width = gameObject.GetComponent<RectTransform>().rect.width;
    8.         float sizeButt = lg.cellSize.x + lg.spacing.x;
    9.         int hSize = Mathf.FloorToInt(width / sizeButt);
    10.         lg.constraintCount = hSize;
    11.     }
     
    frsianturi likes this.
  15. nicloay

    nicloay

    Joined:
    Jul 11, 2012
    Posts:
    397
    It's not properly tested, but I use following script.
    The logic is simple. prior layout calculation just calculate cell size and set it
    Code (csharp):
    1.  
    2. /// <summary>
    3. /// In this class we calculate board cell width height prior layout calculation.
    4. /// </summary>
    5. public class FlexibleGridLayout : GridLayoutGroup
    6. {
    7.    public int ColumnCount = 12;
    8.    public int RowCount = 20;
    9.  
    10.  
    11.    public override void SetLayoutHorizontal()
    12.    {
    13.       UpdateCellSize();
    14.       base.SetLayoutHorizontal();
    15.    }
    16.  
    17.    public override void SetLayoutVertical()
    18.    {
    19.       UpdateCellSize();
    20.       base.SetLayoutVertical();
    21.    }
    22.  
    23.    private void UpdateCellSize()
    24.    {        
    25.       float x = (rectTransform.rect.size.x - padding.horizontal - spacing.x*(ColumnCount - 1)) / ColumnCount;
    26.       float y = (rectTransform.rect.size.y - padding.vertical - spacing.y * (RowCount - 1)) / RowCount;
    27.       this.constraint = Constraint.FixedColumnCount;
    28.       this.constraintCount = ColumnCount;
    29.       this.cellSize = new Vector2(x,y);    
    30.    }
    31. }
    32.  
    And if you want to hide unneded properties and reveal Column, Row count just create Editor script as foloow
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEditor;
    5. using UnityEngine;
    6.  
    7.  
    8. namespace Tetris.UI.Editor
    9. {
    10.  
    11.    [CustomEditor(typeof(TetrisGridLayoutGroup), true)]
    12.    [CanEditMultipleObjects]
    13.    public class FlexibleLayoutGroupEditor : UnityEditor.Editor {
    14.    
    15.       SerializedProperty m_Padding;    
    16.       SerializedProperty m_Spacing;
    17.       SerializedProperty m_StartCorner;
    18.       SerializedProperty m_StartAxis;
    19.       SerializedProperty m_ChildAlignment;
    20.       SerializedProperty m_ColumnCount;
    21.       SerializedProperty m_RowCount;
    22.  
    23.       protected virtual void OnEnable()
    24.       {
    25.          m_Padding = serializedObject.FindProperty("m_Padding");
    26.          m_Spacing = serializedObject.FindProperty("m_Spacing");
    27.          m_StartCorner = serializedObject.FindProperty("m_StartCorner");
    28.          m_StartAxis = serializedObject.FindProperty("m_StartAxis");
    29.          m_ChildAlignment = serializedObject.FindProperty("m_ChildAlignment");
    30.          m_ColumnCount = serializedObject.FindProperty("ColumnCount");
    31.          m_RowCount = serializedObject.FindProperty("RowCount");
    32.       }
    33.  
    34.       public override void OnInspectorGUI()
    35.       {
    36.          serializedObject.Update();
    37.          EditorGUILayout.PropertyField(m_Padding, true);
    38.          EditorGUILayout.PropertyField(m_Spacing, true);
    39.          EditorGUILayout.PropertyField(m_StartCorner, true);
    40.          EditorGUILayout.PropertyField(m_StartAxis, true);
    41.          EditorGUILayout.PropertyField(m_ChildAlignment, true);
    42.          EditorGUILayout.PropertyField(m_ColumnCount, true);
    43.          EditorGUILayout.PropertyField(m_RowCount, true);        
    44.          serializedObject.ApplyModifiedProperties();
    45.       }
    46.    }
    47. }
    48.  
    All of this stuff is based on unity UI source code which is available here:
    https://bitbucket.org/Unity-Technologies/ui
     
  16. mike_unity628

    mike_unity628

    Joined:
    Mar 15, 2018
    Posts:
    1
    Exactly what i needed. Thank you!
     
  17. gamebite10

    gamebite10

    Joined:
    Jan 28, 2018
    Posts:
    1
  18. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    548
    I know this isn't the OP's desire but in case anyone finds themselves here (like I did) looking for solution to maximising the cell size in a GridLayoutGroup, I extended the code snippet above from @jamesburford - HTH

    Code (CSharp):
    1.  
    2. using System;
    3. using UGS.unityutils.attributes;
    4. using UnityEngine;
    5. using UnityEngine.Assertions;
    6. using UnityEngine.UI;
    7.  
    8. namespace ui {
    9.     /// <summary>
    10.     /// Configures a <see cref="GridLayoutGroup.cellSize"/> on same GameObject to have
    11.     /// maximum size for the specified number of rows or columns.
    12.     /// By default, it uses the number from the constraint configured in the <see cref="GridLayoutGroup"/>.
    13.     /// Use the 'override' values here to override or specify a size
    14.     /// when <see cref="GridLayoutGroup.Constraint.Flexible"/> used.
    15.     /// </summary>
    16.     public sealed class GridLayoutMaximiser : MonoBehaviour {
    17.  
    18.         [Tooltip("Override the number of columns to aim for (or zero for default/disabled).\n" +
    19.                 "Takes priority over rows.")]
    20.         [SerializeField]
    21.         private int numColumnsOverride = 0;
    22.  
    23.         [Tooltip("Override the number of rows to aim for (or zero for default/disabled).")]
    24.         [SerializeField]
    25.         private int numRowsOverride = 0;
    26.  
    27.         public void OnValidate() {
    28.             Assert.IsNotNull(transform as RectTransform);
    29.             Assert.IsNotNull(GetComponent<GridLayoutGroup>());
    30.         }
    31.  
    32.         public void OnEnable() {
    33.             setSizes();
    34.         }
    35.  
    36.         [ContextMenu("Set sizes")]
    37.         private void setSizes() {
    38.             var gridLayoutGroup = GetComponent<GridLayoutGroup>();
    39.             var columns = this.numColumnsOverride;
    40.             var rows = this.numRowsOverride;
    41.             switch (gridLayoutGroup.constraint) {
    42.                 case GridLayoutGroup.Constraint.Flexible: // nop
    43.                     break;
    44.  
    45.                 case GridLayoutGroup.Constraint.FixedColumnCount:
    46.                     columns = gridLayoutGroup.constraintCount;
    47.                     break;
    48.  
    49.                 case GridLayoutGroup.Constraint.FixedRowCount:
    50.                     rows = gridLayoutGroup.constraintCount;
    51.                     break;
    52.  
    53.                 default:
    54.                     throw new ArgumentOutOfRangeException(gridLayoutGroup.constraint.ToString());
    55.             }
    56.             var padding = gridLayoutGroup.padding;
    57.             var spacing = gridLayoutGroup.spacing;
    58.             var size = ((RectTransform) transform).rect.size - new Vector2(padding.horizontal, padding.vertical);
    59.             float width, height;
    60.             if (0 < columns) {
    61.                 width = (size.x - (columns - 1) * spacing.x) / columns;
    62.                 if (0 < rows) {
    63.                     height = (size.y - (rows - 1) * spacing.y) / rows;
    64.                 } else {
    65.                     // TODO: account for different vertical to horizontal spacing
    66.                     height = width;
    67.                 }
    68.             } else {
    69.                 if (0 < rows) { // rows specified but not columns
    70.                     // TODO: account for different vertical to horizontal spacing
    71.                     width = height = (size.y - (rows - 1) * spacing.y) / rows;
    72.                 } else { // neither specified
    73.                     return;
    74.                 }
    75.             }
    76.  
    77.             gridLayoutGroup.cellSize = new Vector2(width, height);
    78.         }
    79.  
    80.     }
    81. }
     
  19. MGGDev

    MGGDev

    Joined:
    Nov 6, 2018
    Posts:
    27
    In case someone was trying to make a 'flexible' UI like me and ended up here as well, I went with @lkc2015 logic with some changes. No code needed.

    I wanted to split the grid in 4 equal cells, and when the parent canvas is resized (in different aspect ratios), the cells are also resized automatically, preserving their aspect ratio, and without overlapping each other.
    Here is the hierarchy of objects:
    Root Canvas (Screen Space - Camera)
    -- Flexible Canvas (Vertical Layout Group, with Child Control Size checked in both width and height)
    ---- Row 1 Canvas (Horizontal Layout Group, with Child Control Size checked in both width and height)
    ------ Child Canvas 1
    ------ Child Canvas 2
    ---- Row 2 Canvas (Same as Row 1)
    ------ Child Canvas 3
    ------ Child Canvas 4

    Here is the result
    2ooumw.gif

    Now you can put your own UI objects inside each Canvas and they will resize with it. (You might need to add an Aspect Ratio Fitter to your buttons and UI elements though and set their Rect Transform to Stretch).
    Is there a better way ?
     
    Last edited: Dec 11, 2018
  20. fidelsoto

    fidelsoto

    Joined:
    Aug 7, 2012
    Posts:
    71
    What should I do if I want this:
    upload_2019-3-8_14-35-11.png
     
  21. fidelsoto

    fidelsoto

    Joined:
    Aug 7, 2012
    Posts:
    71
    After days of googling to no avail I was able to hack my own solution:

    Code (CSharp):
    1. /// Credit Simie
    2. /// Sourced from - http://forum.unity3d.com/threads/flowlayoutgroup.296709/
    3. /// Example http://forum.unity3d.com/threads/flowlayoutgroup.296709/
    4. /// Update by Martin Sharkbomb - http://forum.unity3d.com/threads/flowlayoutgroup.296709/#post-1977028
    5. /// Last item alignment fix by Vicente Russo - https://bitbucket.org/ddreaper/unity-ui-extensions/issues/22/flow-layout-group-align
    6. /// Vertical Flow by Ramon Molossi
    7. /// Children auto-resize by Fidel Soto
    8.  
    9. using System.Collections.Generic;
    10.  
    11. namespace UnityEngine.UI.Extensions
    12. {
    13.     /// <summary>
    14.     /// Layout Group controller that arranges children in bars, fitting as many on a line until total size exceeds parent bounds
    15.     /// </summary>
    16.     [AddComponentMenu("Layout/Extensions/Auto Flow Layout Group")]
    17.     public class AutoFlowLayout : LayoutGroup
    18.     {
    19.         public enum Axis { Horizontal = 0, Vertical = 1 }
    20.  
    21.         [Tooltip("Constrains the size of the children to the size they would have at an x amount of items. Leave at 0 to always expand them as much as possible.")]
    22.         public int constrainChildrenSizeToSizeAtCount = 0;
    23.         public Vector2 spacing;
    24.         public bool ExpandHorizontalSpacing = false;
    25.         private Vector2 cellSize;
    26.  
    27.         public bool ChildForceExpandWidth = false;
    28.         public bool ChildForceExpandHeight = false;
    29.         public bool invertOrder = false;
    30.         private float _layoutHeight;
    31.         private float _layoutWidth;
    32.  
    33.         [SerializeField] protected Axis m_StartAxis = Axis.Horizontal;
    34.         public Axis startAxis { get { return m_StartAxis; } set { SetProperty(ref m_StartAxis, value); } }
    35.  
    36.         private void CalculateCellSize()
    37.         {
    38.             int childCount = constrainChildrenSizeToSizeAtCount == 0 || rectChildren.Count >= constrainChildrenSizeToSizeAtCount ? rectChildren.Count : constrainChildrenSizeToSizeAtCount;
    39.             float iColumn;
    40.             if (rectTransform.rect.width >= rectTransform.rect.height)
    41.                 iColumn = Mathf.CeilToInt(Mathf.Sqrt(childCount));
    42.             else
    43.                 iColumn = Mathf.FloorToInt(Mathf.Sqrt(childCount));
    44.             float iRow = Mathf.CeilToInt(childCount / iColumn);
    45.             float fHeight = (rectTransform.rect.height - ((iRow - 1) * (spacing.y))) - ((padding.top + padding.bottom));
    46.             float fWidth = (rectTransform.rect.width - ((iColumn - 1) * (spacing.x))) - ((padding.right + padding.left));
    47.             cellSize = new Vector2(fWidth / iColumn, (fHeight) / iRow);
    48.         }
    49.  
    50.         public override void CalculateLayoutInputHorizontal()
    51.         {
    52.             if (startAxis == Axis.Horizontal)
    53.             {
    54.                 base.CalculateLayoutInputHorizontal();
    55.                 CalculateCellSize();
    56.                 var minWidth = GetGreatestMinimumChildWidth() + padding.left + padding.right;
    57.                 SetLayoutInputForAxis(minWidth, -1, -1, 0);
    58.             }
    59.             else
    60.             {
    61.                 _layoutWidth = SetLayout(0, true);
    62.             }
    63.  
    64.         }
    65.  
    66.         public override void SetLayoutHorizontal()
    67.         {
    68.             SetLayout(0, false);
    69.         }
    70.  
    71.         public override void SetLayoutVertical()
    72.         {
    73.             SetLayout(1, false);
    74.         }
    75.  
    76.         public override void CalculateLayoutInputVertical()
    77.         {
    78.             if (startAxis == Axis.Horizontal)
    79.             {
    80.                 _layoutHeight = SetLayout(1, true);
    81.             }
    82.             else
    83.             {
    84.                 base.CalculateLayoutInputHorizontal();
    85.                 CalculateCellSize();
    86.                 var minHeight = GetGreatestMinimumChildHeigth() + padding.bottom + padding.top;
    87.                 SetLayoutInputForAxis(minHeight, -1, -1, 1);
    88.             }
    89.         }
    90.  
    91.         protected bool IsCenterAlign
    92.         {
    93.             get
    94.             {
    95.                 return childAlignment == TextAnchor.LowerCenter || childAlignment == TextAnchor.MiddleCenter ||
    96.                     childAlignment == TextAnchor.UpperCenter;
    97.             }
    98.         }
    99.  
    100.         protected bool IsRightAlign
    101.         {
    102.             get
    103.             {
    104.                 return childAlignment == TextAnchor.LowerRight || childAlignment == TextAnchor.MiddleRight ||
    105.                     childAlignment == TextAnchor.UpperRight;
    106.             }
    107.         }
    108.  
    109.         protected bool IsMiddleAlign
    110.         {
    111.             get
    112.             {
    113.                 return childAlignment == TextAnchor.MiddleLeft || childAlignment == TextAnchor.MiddleRight ||
    114.                     childAlignment == TextAnchor.MiddleCenter;
    115.             }
    116.         }
    117.  
    118.         protected bool IsLowerAlign
    119.         {
    120.             get
    121.             {
    122.                 return childAlignment == TextAnchor.LowerLeft || childAlignment == TextAnchor.LowerRight ||
    123.                     childAlignment == TextAnchor.LowerCenter;
    124.             }
    125.         }
    126.  
    127.         /// <summary>
    128.         /// Holds the rects that will make up the current bar being processed
    129.         /// </summary>
    130.         private readonly IList<RectTransform> _itemList = new List<RectTransform>();
    131.  
    132.         /// <summary>
    133.         /// Main layout method
    134.         /// </summary>
    135.         /// <param name="width">Width to calculate the layout with</param>
    136.         /// <param name="axis">0 for horizontal axis, 1 for vertical</param>
    137.         /// <param name="layoutInput">If true, sets the layout input for the axis. If false, sets child position for axis</param>
    138.         public float SetLayout(int axis, bool layoutInput)
    139.         {
    140.             //container height and width
    141.             var groupHeight = rectTransform.rect.height;
    142.             var groupWidth = rectTransform.rect.width;
    143.  
    144.             float spacingBetweenBars = 0;
    145.             float spacingBetweenElements = 0;
    146.             float offset = 0;
    147.             float counterOffset = 0;
    148.             float groupSize = 0;
    149.             float workingSize = 0;
    150.             if (startAxis == Axis.Horizontal)
    151.             {
    152.                 groupSize = groupHeight;
    153.                 workingSize = groupWidth - padding.left - padding.right;
    154.                 if (IsLowerAlign)
    155.                 {
    156.                     offset = (float)padding.bottom;
    157.                     counterOffset = (float)padding.top;
    158.                 }
    159.                 else
    160.                 {
    161.                     offset = (float)padding.top;
    162.                     counterOffset = (float)padding.bottom;
    163.                 }
    164.                 spacingBetweenBars = spacing.y;
    165.                 spacingBetweenElements = spacing.x;
    166.             }
    167.             else if (startAxis == Axis.Vertical)
    168.             {
    169.                 groupSize = groupWidth;
    170.                 workingSize = groupHeight - padding.top - padding.bottom;
    171.                 if (IsRightAlign)
    172.                 {
    173.                     offset = (float)padding.right;
    174.                     counterOffset = (float)padding.left;
    175.                 }
    176.                 else
    177.                 {
    178.                     offset = (float)padding.left;
    179.                     counterOffset = (float)padding.right;
    180.                 }
    181.                 spacingBetweenBars = spacing.x;
    182.                 spacingBetweenElements = spacing.y;
    183.             }
    184.  
    185.             var currentBarSize = 0f;
    186.             var currentBarSpace = 0f;
    187.  
    188.             for (var i = 0; i < rectChildren.Count; i++)
    189.             {
    190.  
    191.                 int index = i;
    192.                 var child = rectChildren[index];
    193.                 float childSize = 0;
    194.                 float childOtherSize = 0;
    195.                 //get height and width of elements.
    196.                 if (startAxis == Axis.Horizontal)
    197.                 {
    198.                     if (invertOrder)
    199.                     {
    200.                         index = IsLowerAlign ? rectChildren.Count - 1 - i : i;
    201.                     }
    202.                     child = rectChildren[index];
    203.                     //childSize = LayoutUtility.GetPreferredSize (child, 0);
    204.                     //childSize = Mathf.Min (childSize, workingSize);
    205.                     //childOtherSize = LayoutUtility.GetPreferredSize (child, 1);
    206.                     //childOtherSize = Mathf.Min (childOtherSize, workingSize);
    207.                     childSize = cellSize.x;
    208.                     childOtherSize = cellSize.y;
    209.                     child.sizeDelta = cellSize;
    210.                 }
    211.                 else if (startAxis == Axis.Vertical)
    212.                 {
    213.                     if (invertOrder)
    214.                     {
    215.                         index = IsRightAlign ? rectChildren.Count - 1 - i : i;
    216.                     }
    217.                     child = rectChildren[index];
    218.                     //childSize = LayoutUtility.GetPreferredSize (child, 1);
    219.                     //childSize = Mathf.Min (childSize, workingSize);
    220.                     //childOtherSize = LayoutUtility.GetPreferredSize (child, 0);
    221.                     //childOtherSize = Mathf.Min (childOtherSize, workingSize);
    222.                     childSize = cellSize.y;
    223.                     childOtherSize = cellSize.x;
    224.                     child.sizeDelta = cellSize;
    225.                 }
    226.  
    227.                 // If adding this element would exceed the bounds of the container,
    228.                 // go to a new bar after processing the current bar
    229.                 if (currentBarSize + childSize > workingSize && !(Mathf.Approximately(currentBarSize + childSize, workingSize)))
    230.                 {
    231.  
    232.                     currentBarSize -= spacingBetweenElements;
    233.  
    234.                     // Process current bar elements positioning
    235.                     if (!layoutInput)
    236.                     {
    237.                         if (startAxis == Axis.Horizontal)
    238.                         {
    239.                             float newOffset = CalculateRowVerticalOffset(groupSize, offset, currentBarSpace);
    240.                             LayoutRow(_itemList, currentBarSize, currentBarSpace, workingSize, padding.left, newOffset, axis);
    241.                         }
    242.                         else if (startAxis == Axis.Vertical)
    243.                         {
    244.                             float newOffset = CalculateColHorizontalOffset(groupSize, offset, currentBarSpace);
    245.                             LayoutCol(_itemList, currentBarSpace, currentBarSize, workingSize, newOffset, padding.top, axis);
    246.                         }
    247.                     }
    248.  
    249.                     // Clear existing bar
    250.                     _itemList.Clear();
    251.  
    252.                     // Add the current bar space to total barSpace accumulator, and reset to 0 for the next row
    253.                     offset += currentBarSpace;
    254.                     offset += spacingBetweenBars;
    255.  
    256.                     currentBarSpace = 0;
    257.                     currentBarSize = 0;
    258.  
    259.                 }
    260.  
    261.                 currentBarSize += childSize;
    262.                 _itemList.Add(child);
    263.  
    264.                 // We need the largest element height to determine the starting position of the next line
    265.                 if (childOtherSize > currentBarSpace)
    266.                 {
    267.                     currentBarSpace = childOtherSize;
    268.                 }
    269.  
    270.                 // Don't do this for the last one
    271.                 if (i < rectChildren.Count - 1)
    272.                 {
    273.                     currentBarSize += spacingBetweenElements;
    274.                 }
    275.  
    276.             }
    277.  
    278.             // Layout the final bar
    279.             if (!layoutInput)
    280.             {
    281.                 if (startAxis == Axis.Horizontal)
    282.                 {
    283.                     float newOffset = CalculateRowVerticalOffset(groupHeight, offset, currentBarSpace);
    284.                     currentBarSize -= spacingBetweenElements;
    285.                     LayoutRow(_itemList, currentBarSize, currentBarSpace, workingSize - (ChildForceExpandWidth ? 0 : spacingBetweenElements), padding.left, newOffset, axis);
    286.                 }
    287.                 else if (startAxis == Axis.Vertical)
    288.                 {
    289.                     float newOffset = CalculateColHorizontalOffset(groupWidth, offset, currentBarSpace);
    290.                     currentBarSize -= spacingBetweenElements;
    291.                     LayoutCol(_itemList, currentBarSpace, currentBarSize, workingSize - (ChildForceExpandHeight ? 0 : spacingBetweenElements), newOffset, padding.top, axis);
    292.                 }
    293.             }
    294.  
    295.             _itemList.Clear();
    296.  
    297.             // Add the last bar space to the barSpace accumulator
    298.             offset += currentBarSpace;
    299.             offset += counterOffset;
    300.  
    301.             if (layoutInput)
    302.             {
    303.                 SetLayoutInputForAxis(offset, offset, -1, axis);
    304.             }
    305.             return offset;
    306.         }
    307.  
    308.         private float CalculateRowVerticalOffset(float groupHeight, float yOffset, float currentRowHeight)
    309.         {
    310.             if (IsLowerAlign)
    311.             {
    312.                 return groupHeight - yOffset - currentRowHeight;
    313.             }
    314.             else if (IsMiddleAlign)
    315.             {
    316.                 return groupHeight * 0.5f - _layoutHeight * 0.5f + yOffset;
    317.             }
    318.             else
    319.             {
    320.                 return yOffset;
    321.             }
    322.         }
    323.  
    324.         private float CalculateColHorizontalOffset(float groupWidth, float xOffset, float currentColWidth)
    325.         {
    326.             if (IsRightAlign)
    327.             {
    328.                 return groupWidth - xOffset - currentColWidth;
    329.             }
    330.             else if (IsCenterAlign)
    331.             {
    332.                 return groupWidth * 0.5f - _layoutWidth * 0.5f + xOffset;
    333.             }
    334.             else
    335.             {
    336.                 return xOffset;
    337.             }
    338.         }
    339.  
    340.         protected void LayoutRow(IList<RectTransform> contents, float rowWidth, float rowHeight, float maxWidth, float xOffset, float yOffset, int axis)
    341.         {
    342.             var xPos = xOffset;
    343.  
    344.             if (!ChildForceExpandWidth && IsCenterAlign)
    345.             {
    346.                 xPos += (maxWidth - rowWidth) * 0.5f;
    347.             }
    348.             else if (!ChildForceExpandWidth && IsRightAlign)
    349.             {
    350.                 xPos += (maxWidth - rowWidth);
    351.             }
    352.  
    353.             var extraWidth = 0f;
    354.             var extraSpacing = 0f;
    355.  
    356.             if (ChildForceExpandWidth)
    357.             {
    358.                 extraWidth = (maxWidth - rowWidth) / _itemList.Count;
    359.             }
    360.             else if (ExpandHorizontalSpacing)
    361.             {
    362.                 extraSpacing = (maxWidth - rowWidth) / (_itemList.Count - 1);
    363.                 if (_itemList.Count > 1)
    364.                 {
    365.                     if (IsCenterAlign)
    366.                     {
    367.                         xPos -= extraSpacing * 0.5f * (_itemList.Count - 1);
    368.                     }
    369.                     else if (IsRightAlign)
    370.                     {
    371.                         xPos -= extraSpacing * (_itemList.Count - 1);
    372.                     }
    373.                 }
    374.             }
    375.  
    376.             for (var j = 0; j < _itemList.Count; j++)
    377.             {
    378.  
    379.                 var index = IsLowerAlign ? _itemList.Count - 1 - j : j;
    380.  
    381.                 var rowChild = _itemList[index];
    382.  
    383.                 var rowChildWidth = cellSize.x + extraWidth; //LayoutUtility.GetPreferredSize(rowChild, 0) + extraWidth;
    384.                 var rowChildHeight = cellSize.y; //LayoutUtility.GetPreferredSize(rowChild, 1);
    385.  
    386.                 if (ChildForceExpandHeight)
    387.                     rowChildHeight = rowHeight;
    388.  
    389.                 rowChildWidth = Mathf.Min(rowChildWidth, maxWidth);
    390.  
    391.                 var yPos = yOffset;
    392.  
    393.                 if (IsMiddleAlign)
    394.                 {
    395.                     yPos += (rowHeight - rowChildHeight) * 0.5f;
    396.                 }
    397.                 else if (IsLowerAlign)
    398.                 {
    399.                     yPos += (rowHeight - rowChildHeight);
    400.                 }
    401.  
    402.                 if (ExpandHorizontalSpacing && j > 0)
    403.                 {
    404.                     xPos += extraSpacing;
    405.                 }
    406.  
    407.                 if (axis == 0)
    408.                 {
    409.                     SetChildAlongAxis(rowChild, 0, xPos, rowChildWidth);
    410.                 }
    411.                 else
    412.                 {
    413.                     SetChildAlongAxis(rowChild, 1, yPos, rowChildHeight);
    414.                 }
    415.  
    416.                 // Don't do horizontal spacing for the last one
    417.                 if (j < _itemList.Count - 1)
    418.                 {
    419.                     xPos += rowChildWidth + spacing.x;
    420.                 }
    421.             }
    422.         }
    423.  
    424.         protected void LayoutCol(IList<RectTransform> contents, float colWidth, float colHeight, float maxHeight, float xOffset, float yOffset, int axis)
    425.         {
    426.             var yPos = yOffset;
    427.  
    428.             if (!ChildForceExpandHeight && IsMiddleAlign)
    429.             {
    430.                 yPos += (maxHeight - colHeight) * 0.5f;
    431.             }
    432.             else if (!ChildForceExpandHeight && IsLowerAlign)
    433.             {
    434.                 yPos += (maxHeight - colHeight);
    435.             }
    436.  
    437.             var extraHeight = 0f;
    438.             var extraSpacing = 0f;
    439.  
    440.             if (ChildForceExpandHeight)
    441.             {
    442.                 extraHeight = (maxHeight - colHeight) / _itemList.Count;
    443.             }
    444.             else if (ExpandHorizontalSpacing)
    445.             {
    446.                 extraSpacing = (maxHeight - colHeight) / (_itemList.Count - 1);
    447.                 if (_itemList.Count > 1)
    448.                 {
    449.                     if (IsMiddleAlign)
    450.                     {
    451.                         yPos -= extraSpacing * 0.5f * (_itemList.Count - 1);
    452.                     }
    453.                     else if (IsLowerAlign)
    454.                     {
    455.                         yPos -= extraSpacing * (_itemList.Count - 1);
    456.                     }
    457.                 }
    458.             }
    459.  
    460.             for (var j = 0; j < _itemList.Count; j++)
    461.             {
    462.  
    463.                 var index = IsRightAlign ? _itemList.Count - 1 - j : j;
    464.  
    465.                 var rowChild = _itemList[index];
    466.  
    467.                 var rowChildWidth = cellSize.x; //LayoutUtility.GetPreferredSize(rowChild, 0) ;
    468.                 var rowChildHeight = cellSize.y + extraHeight; //LayoutUtility.GetPreferredSize(rowChild, 1) + extraHeight;
    469.  
    470.                 if (ChildForceExpandWidth)
    471.                 {
    472.                     rowChildWidth = colWidth;
    473.                 }
    474.  
    475.                 rowChildHeight = Mathf.Min(rowChildHeight, maxHeight);
    476.  
    477.                 var xPos = xOffset;
    478.  
    479.                 if (IsCenterAlign)
    480.                 {
    481.                     xPos += (colWidth - rowChildWidth) * 0.5f;
    482.                 }
    483.                 else if (IsRightAlign)
    484.                 {
    485.                     xPos += (colWidth - rowChildWidth);
    486.                 }
    487.  
    488.                 //
    489.                 if (ExpandHorizontalSpacing && j > 0)
    490.                 {
    491.                     yPos += extraSpacing;
    492.                 }
    493.  
    494.                 if (axis == 0)
    495.                 {
    496.                     SetChildAlongAxis(rowChild, 0, xPos, rowChildWidth);
    497.                 }
    498.                 else
    499.                 {
    500.                     SetChildAlongAxis(rowChild, 1, yPos, rowChildHeight);
    501.                 }
    502.  
    503.                 // Don't do vertical spacing for the last one
    504.                 if (j < _itemList.Count - 1)
    505.                 {
    506.                     yPos += rowChildHeight + spacing.y;
    507.                 }
    508.             }
    509.         }
    510.  
    511.         public float GetGreatestMinimumChildWidth()
    512.         {
    513.             var max = 0f;
    514.             for (var i = 0; i < rectChildren.Count; i++)
    515.             {
    516.                 var w = LayoutUtility.GetMinWidth(rectChildren[i]);
    517.  
    518.                 max = Mathf.Max(w, max);
    519.             }
    520.             return max;
    521.         }
    522.  
    523.         public float GetGreatestMinimumChildHeigth()
    524.         {
    525.             var max = 0f;
    526.             for (var i = 0; i < rectChildren.Count; i++)
    527.             {
    528.                 var w = LayoutUtility.GetMinHeight(rectChildren[i]);
    529.  
    530.                 max = Mathf.Max(w, max);
    531.             }
    532.             return max;
    533.         }
    534.     }
    535. }
    It is an extension/edit of the FlowLayoutGroup in the UnityUIExtensions repository.
    Children in the layout container will resize automatically in order to fit inside the container.
    You can choose the children alignment. If you select middle-center the leftovers will align in the middle-center as shown in the picture on my previous post.
     
    Last edited: Mar 15, 2019
  22. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    502
    It says that
    gridLayout.cellSize
    is readOnly so what the hell am I supposed to do?

    I need to resize a grid of objects to fit the screen size but it doesn't seem possible to do automatically OR manually.
     
  23. fidelsoto

    fidelsoto

    Joined:
    Aug 7, 2012
    Posts:
    71
    It says cellSize is ready only because it is a Unity Vector3. You can assign to cellSize.x and cellSize.y.
    Anyways... have you tried my FlowLayoutGroup edit shown above?
     
  24. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    502
    gridLayout.cellSize itself behaved as readonly.

    I used some flexible grid layout from the other forum thread, thanks.