Search Unity

Flexible "grid" layout?

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

  1. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    977
    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,689
    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:
    977
    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:
    850
    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:
    977
    Last edited: Feb 5, 2015
    MilenaRocha likes this.
  6. Pix10

    Pix10

    Joined:
    Jul 21, 2012
    Posts:
    850
    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,689
    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
     
  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
     
  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!
     
    nov2479, Acoustic125, Arkade and 2 others 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:
     
  12. XiongGuiYang

    XiongGuiYang

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

    Attached Files:

    addray likes this.
  13. Harinezumi

    Harinezumi

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

    Sudarmin-Then

    Joined:
    Nov 27, 2014
    Posts:
    27
    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.     }
     
    Highavenue01 and frsianturi like this.
  15. nicloay

    nicloay

    Joined:
    Jul 11, 2012
    Posts:
    540
    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
    wmadwand and Canthus like this.
  18. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    655
    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. }
     
    Sologamer and khaled24 like this.
  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
    Maeslezo likes this.
  20. fidelsoto

    fidelsoto

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

    fidelsoto

    Joined:
    Aug 7, 2012
    Posts:
    87
    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:
    863
    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:
    87
    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:
    863
    gridLayout.cellSize itself behaved as readonly.

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

    CorentinSimango

    Joined:
    Mar 26, 2019
    Posts:
    1
    Hi @illinar

    What's the flexible grid layout you use, I cannot find anything who suits me...
     
  26. Ipolitas

    Ipolitas

    Joined:
    Oct 12, 2016
    Posts:
    1
    This is gold! I was struggling with this problem forever!
     
  27. linfuqing

    linfuqing

    Joined:
    May 11, 2015
    Posts:
    166
    here's my Grid layout group:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3.  
    4. namespace ZG
    5. {
    6.     [ExecuteAlways]
    7.     public class GridLayoutGroupEx : LayoutGroup
    8.     {
    9.         /// <summary>
    10.         /// The grid axis we are looking at.
    11.         /// </summary>
    12.         /// <remarks>
    13.         /// As the storage is a [][] we make access easier by passing a axis.
    14.         /// </remarks>
    15.         public enum Axis
    16.         {
    17.             /// <summary>
    18.             /// Horizontal axis
    19.             /// </summary>
    20.             Horizontal = 0,
    21.             /// <summary>
    22.             /// Vertical axis.
    23.             /// </summary>
    24.             Vertical = 1
    25.         }
    26.        
    27.         [SerializeField] internal Axis _startAxis = Axis.Horizontal;
    28.  
    29.         /// <summary>
    30.         /// Which axis should cells be placed along first
    31.         /// </summary>
    32.         /// <remarks>
    33.         /// When startAxis is set to horizontal, an entire row will be filled out before proceeding to the next row. When set to vertical, an entire column will be filled out before proceeding to the next column.
    34.         /// </remarks>
    35.         public Axis startAxis { get { return _startAxis; } set { SetProperty(ref _startAxis, value); } }
    36.  
    37.         [SerializeField] internal int _constraintCount = 0;
    38.  
    39.         /// <summary>
    40.         /// How many cells there should be along the constrained axis.
    41.         /// </summary>
    42.         public int constraintCount { get { return _constraintCount == 0 ? rectChildren.Count : _constraintCount; } set { SetProperty(ref _constraintCount, value); } }
    43.  
    44.         [SerializeField] internal Vector2 _spacing = Vector2.zero;
    45.  
    46.         /// <summary>
    47.         /// The spacing to use between layout elements in the grid on both axises.
    48.         /// </summary>
    49.         public Vector2 spacing { get { return _spacing; } set { SetProperty(ref _spacing, value); } }
    50.        
    51.         [SerializeField] internal bool _childForceExpandWidth = true;
    52.  
    53.         /// <summary>
    54.         /// Whether to force the children to expand to fill additional available horizontal space.
    55.         /// </summary>
    56.         public bool childForceExpandWidth { get { return _childForceExpandWidth; } set { SetProperty(ref _childForceExpandWidth, value); } }
    57.  
    58.         [SerializeField] internal bool _childForceExpandHeight = true;
    59.  
    60.         /// <summary>
    61.         /// Whether to force the children to expand to fill additional available vertical space.
    62.         /// </summary>
    63.         public bool childForceExpandHeight { get { return _childForceExpandHeight; } set { SetProperty(ref _childForceExpandHeight, value); } }
    64.  
    65.         [SerializeField] internal bool _childControlWidth = true;
    66.  
    67.         /// <summary>
    68.         /// Returns true if the Layout Group controls the widths of its children. Returns false if children control their own widths.
    69.         /// </summary>
    70.         /// <remarks>
    71.         /// If set to false, the layout group will only affect the positions of the children while leaving the widths untouched. The widths of the children can be set via the respective RectTransforms in this case.
    72.         ///
    73.         /// If set to true, the widths of the children are automatically driven by the layout group according to their respective minimum, preferred, and flexible widths. This is useful if the widths of the children should change depending on how much space is available.In this case the width of each child cannot be set manually in the RectTransform, but the minimum, preferred and flexible width for each child can be controlled by adding a LayoutElement component to it.
    74.         /// </remarks>
    75.         public bool childControlWidth { get { return _childControlWidth; } set { SetProperty(ref _childControlWidth, value); } }
    76.  
    77.         [SerializeField] internal bool _childControlHeight = true;
    78.  
    79.         /// <summary>
    80.         /// Returns true if the Layout Group controls the heights of its children. Returns false if children control their own heights.
    81.         /// </summary>
    82.         /// <remarks>
    83.         /// If set to false, the layout group will only affect the positions of the children while leaving the heights untouched. The heights of the children can be set via the respective RectTransforms in this case.
    84.         ///
    85.         /// If set to true, the heights of the children are automatically driven by the layout group according to their respective minimum, preferred, and flexible heights. This is useful if the heights of the children should change depending on how much space is available.In this case the height of each child cannot be set manually in the RectTransform, but the minimum, preferred and flexible height for each child can be controlled by adding a LayoutElement component to it.
    86.         /// </remarks>
    87.         public bool childControlHeight { get { return _childControlHeight; } set { SetProperty(ref _childControlHeight, value); } }
    88.  
    89.         [SerializeField] internal bool _childScaleWidth = false;
    90.  
    91.         /// <summary>
    92.         /// Whether children widths are scaled by their x scale.
    93.         /// </summary>
    94.         public bool childScaleWidth { get { return _childScaleWidth; } set { SetProperty(ref _childScaleWidth, value); } }
    95.  
    96.         [SerializeField] internal bool _childScaleHeight = false;
    97.  
    98.         /// <summary>
    99.         /// Whether children heights are scaled by their y scale.
    100.         /// </summary>
    101.         public bool childScaleHeight { get { return _childScaleHeight; } set { SetProperty(ref _childScaleHeight, value); } }
    102.        
    103.         /// <summary>
    104.         /// Called by the layout system to calculate the horizontal layout size.
    105.         /// Also see ILayoutElement
    106.         /// </summary>
    107.         public override void CalculateLayoutInputHorizontal()
    108.         {
    109.             base.CalculateLayoutInputHorizontal();
    110.  
    111.             __SetLayoutAlongForAxis(startAxis == Axis.Vertical, 0);
    112.         }
    113.  
    114.         /// <summary>
    115.         /// Called by the layout system to calculate the vertical layout size.
    116.         /// Also see ILayoutElement
    117.         /// </summary>
    118.         public override void CalculateLayoutInputVertical()
    119.         {
    120.             __SetLayoutAlongForAxis(startAxis == Axis.Vertical, 1);
    121.         }
    122.        
    123.         /// <summary>
    124.         /// Called by the layout system
    125.         /// Also see ILayoutElement
    126.         /// </summary>
    127.         public override void SetLayoutHorizontal()
    128.         {
    129.             //SetCellsAlongAxis(0);
    130.            
    131.             __SetChildrenAlongAxis(0, startAxis == Axis.Vertical);
    132.         }
    133.  
    134.         /// <summary>
    135.         /// Called by the layout system
    136.         /// Also see ILayoutElement
    137.         /// </summary>
    138.         public override void SetLayoutVertical()
    139.         {
    140.             //SetCellsAlongAxis(1);
    141.  
    142.             __SetChildrenAlongAxis(1, startAxis == Axis.Vertical);
    143.         }
    144.        
    145.         /// <summary>
    146.         /// Calculate the layout element properties for this layout element along the given axis.
    147.         /// </summary>
    148.         /// <param name="axis">The axis to calculate for. 0 is horizontal and 1 is vertical.</param>
    149.         /// <param name="isVertical">Is this group a vertical group?</param>
    150.         private void __CalcAlongAxis(
    151.             bool isVertical,
    152.             int axis,
    153.             int startRectChildernIndex,
    154.             int rectChildrenCount,
    155.             out float totalMin,
    156.             out float totalPreferred,
    157.             out float totalFlexible)
    158.         {
    159.             float /*combinedPadding = (axis == 0 ? padding.horizontal : padding.vertical), */spacing = this.spacing[axis];
    160.             bool controlSize = (axis == 0 ? _childControlWidth : _childControlHeight),
    161.                 useScale = (axis == 0 ? _childScaleWidth : _childScaleHeight),
    162.                 childForceExpandSize = (axis == 0 ? _childForceExpandWidth : _childForceExpandHeight);
    163.  
    164.             totalMin = 0.0f;// combinedPadding;
    165.             totalPreferred = 0.0f;// combinedPadding;
    166.             totalFlexible = 0;
    167.  
    168.             bool alongOtherAxis = (isVertical ^ (axis == 1));
    169.             for (int i = 0; i < rectChildrenCount; i++)
    170.             {
    171.                 RectTransform child = rectChildren[i + startRectChildernIndex];
    172.                 float min, preferred, flexible;
    173.                 GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible);
    174.  
    175.                 if (useScale)
    176.                 {
    177.                     float scaleFactor = child.localScale[axis];
    178.                     min *= scaleFactor;
    179.                     preferred *= scaleFactor;
    180.                     flexible *= scaleFactor;
    181.                 }
    182.  
    183.                 if (alongOtherAxis)
    184.                 {
    185.                     totalMin = Mathf.Max(min/* + combinedPadding*/, totalMin);
    186.                     totalPreferred = Mathf.Max(preferred/* + combinedPadding*/, totalPreferred);
    187.                     totalFlexible = Mathf.Max(flexible, totalFlexible);
    188.                 }
    189.                 else
    190.                 {
    191.                     totalMin += min + spacing;
    192.                     totalPreferred += preferred + spacing;
    193.  
    194.                     // Increment flexible size with element's flexible size.
    195.                     totalFlexible += flexible;
    196.                 }
    197.             }
    198.  
    199.             if (!alongOtherAxis && rectChildren.Count > 0)
    200.             {
    201.                 totalMin -= spacing;
    202.                 totalPreferred -= spacing;
    203.             }
    204.             totalPreferred = Mathf.Max(totalMin, totalPreferred);
    205.         }
    206.  
    207.         private void __SetLayoutAlongForAxis(bool isVertical, int axis)
    208.         {
    209.             bool alongOtherAxis = (isVertical ^ (axis == 1));
    210.             int rectChildrenCount = rectChildren.Count;
    211.             float combinedPadding = (axis == 0 ? padding.horizontal : padding.vertical),
    212.                 spacing = this.spacing[axis],
    213.                 totalMin = combinedPadding,
    214.                 totalPreferred = combinedPadding,
    215.                 totalFlexble = 0.0f,
    216.                 min, preferred, flexible;
    217.             for (int i = 0; i < rectChildrenCount; i += constraintCount)
    218.             {
    219.                 __CalcAlongAxis(isVertical, axis, i, Mathf.Min(rectChildrenCount - i, constraintCount), out min, out preferred, out flexible);
    220.  
    221.                 if (alongOtherAxis)
    222.                 {
    223.                     totalMin += min + spacing;
    224.                     totalPreferred += preferred + spacing;
    225.                     totalFlexble += flexible;
    226.                 }
    227.                 else
    228.                 {
    229.                     totalMin = Mathf.Max(min + combinedPadding, totalMin);
    230.                     totalPreferred = Mathf.Max(preferred + combinedPadding, totalPreferred);
    231.                     totalFlexble = Mathf.Max(flexible, totalFlexble);
    232.                 }
    233.             }
    234.  
    235.             if (alongOtherAxis && rectChildrenCount > 0)
    236.             {
    237.                 totalMin -= spacing;
    238.                 totalPreferred -= spacing;
    239.             }
    240.  
    241.             totalPreferred = Mathf.Max(totalMin, totalPreferred);
    242.  
    243.             SetLayoutInputForAxis(
    244.                 totalMin,
    245.                 totalPreferred,
    246.                 totalFlexble,
    247.                 axis);
    248.         }
    249.  
    250.         /// <summary>
    251.         /// Set the positions and sizes of the child layout elements for the given axis.
    252.         /// </summary>
    253.         /// <param name="axis">The axis to handle. 0 is horizontal and 1 is vertical.</param>
    254.         /// <param name="isVertical">Is this group a vertical group?</param>
    255.         private void __SetChildrenAlongAxis(int axis, bool isVertical)
    256.         {
    257.             float size = rectTransform.rect.size[axis],
    258.                 combinedPadding = (axis == 0 ? padding.horizontal : padding.vertical),
    259.                 spacing = this.spacing[axis],
    260.                 alignmentOnAxis = GetAlignmentOnAxis(axis);
    261.             bool controlSize = (axis == 0 ? _childControlWidth : _childControlHeight);
    262.             bool useScale = (axis == 0 ? _childScaleWidth : _childScaleHeight);
    263.             bool childForceExpandSize = (axis == 0 ? _childForceExpandWidth : _childForceExpandHeight);
    264.  
    265.             bool alongOtherAxis = (isVertical ^ (axis == 1));
    266.             if (alongOtherAxis)
    267.             {
    268.                 float startOffset = 0;
    269.  
    270.                 float itemFlexibleMultiplier = 0.0f, totalMin = GetTotalMinSize(axis), totalPreferred = GetTotalPreferredSize(axis), totalFlexible = GetTotalFlexibleSize(axis);
    271.  
    272.                 float surplusSpace = size - totalPreferred;
    273.                 if (surplusSpace > 0.0f)
    274.                 {
    275.                     if (totalFlexible > 0.0f)
    276.                         itemFlexibleMultiplier = surplusSpace / totalFlexible;
    277.                     else if (totalFlexible == 0.0f)
    278.                         startOffset = GetStartOffset(axis, totalPreferred - (axis == 0 ? padding.horizontal : padding.vertical)) - (axis == 0 ? padding.left : padding.top);
    279.                 }
    280.  
    281.                 float minMaxLerp = 0.0f;
    282.                 if (totalMin != totalPreferred)
    283.                     minMaxLerp = Mathf.Clamp01((size - totalMin) / (totalPreferred - totalMin));
    284.  
    285.                 float innerSize = size - combinedPadding, maxSpace = 0.0f;
    286.                 for (int i = 0; i < rectChildren.Count; i++)
    287.                 {
    288.                     RectTransform child = rectChildren[i];
    289.                     float min, preferred, flexible;
    290.                     GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible);
    291.                     float scaleFactor = useScale ? child.localScale[axis] : 1f;
    292.                     //float requiredSpace = Mathf.Clamp(innerSize, min, flexible > 0 ? size : preferred);
    293.                     //space = requiredSpace * scaleFactor;
    294.                     float requiredSpace = Mathf.Lerp(min, preferred, minMaxLerp);
    295.                     requiredSpace += flexible * itemFlexibleMultiplier;
    296.                     float space = requiredSpace * scaleFactor;
    297.                     if (i % constraintCount == 0)
    298.                     {
    299.                         if (i != 0)
    300.                             startOffset += maxSpace + spacing;
    301.  
    302.                         __CalcAlongAxis(
    303.                             isVertical,
    304.                             axis,
    305.                             i + 1,
    306.                             Mathf.Min(rectChildren.Count - i, constraintCount) - 1,
    307.                             out totalMin,
    308.                             out totalPreferred,
    309.                             out totalFlexible);
    310.  
    311.                         maxSpace = Mathf.Max(space, Mathf.Lerp(totalMin, totalPreferred, minMaxLerp) + totalFlexible * itemFlexibleMultiplier);
    312.                     }
    313.  
    314.                     float offset = startOffset + GetStartOffset(axis, innerSize - maxSpace + space);
    315.                     //float startOffset = GetStartOffset(axis, innerSize - maxSpace + space);
    316.                     //maxOffset = Mathf.Max(maxOffset, startOffset + requiredSpace);
    317.                     //maxSpace = Mathf.Max(maxSpace, requiredSpace * scaleFactor);
    318.                     if (controlSize)
    319.                     {
    320.                         SetChildAlongAxisWithScale(child, axis, offset, requiredSpace, scaleFactor);
    321.                     }
    322.                     else
    323.                     {
    324.                         float offsetInCell = (requiredSpace - child.sizeDelta[axis]) * alignmentOnAxis;
    325.                         SetChildAlongAxisWithScale(child, axis, offset + offsetInCell, scaleFactor);
    326.                     }
    327.                 }
    328.             }
    329.             else
    330.             {
    331.                 float startPos = (axis == 0 ? padding.left : padding.top), pos = startPos, itemFlexibleMultiplier = 0.0f, minMaxLerp = 0.0f;
    332.                
    333.                 for (int i = 0; i < rectChildren.Count; i++)
    334.                 {
    335.                     RectTransform child = rectChildren[i];
    336.                     float min, preferred, flexible;
    337.                     GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible);
    338.                     float scaleFactor = useScale ? child.localScale[axis] : 1f;
    339.  
    340.                     if (i % constraintCount == 0)
    341.                     {
    342.                         pos = startPos;
    343.  
    344.                         __CalcAlongAxis(isVertical,
    345.                             axis,
    346.                             i,
    347.                             Mathf.Min(rectChildren.Count - i, constraintCount),
    348.                             out float totalMin,
    349.                             out float totalPreferred,
    350.                             out float totalFlexible);
    351.  
    352.                         totalMin += combinedPadding;
    353.                         totalPreferred += combinedPadding;
    354.  
    355.                         itemFlexibleMultiplier = 0.0f;
    356.  
    357.                         float surplusSpace = size - totalPreferred;
    358.                         if (surplusSpace > 0.0f)
    359.                         {
    360.                             if (totalFlexible > 0.0f)
    361.                                 itemFlexibleMultiplier = surplusSpace / totalFlexible;
    362.                             else if(totalFlexible == 0.0f)
    363.                                 pos = GetStartOffset(axis, totalPreferred - (axis == 0 ? padding.horizontal : padding.vertical));
    364.                         }
    365.  
    366.                         minMaxLerp = 0.0f;
    367.                         if (totalMin != totalPreferred)
    368.                             minMaxLerp = Mathf.Clamp01((size - totalMin) / (totalPreferred - totalMin));
    369.                     }
    370.  
    371.                     float childSize = Mathf.Lerp(min, preferred, minMaxLerp);
    372.                     childSize += flexible * itemFlexibleMultiplier;
    373.                     if (controlSize)
    374.                     {
    375.                         SetChildAlongAxisWithScale(child, axis, pos, childSize, scaleFactor);
    376.                     }
    377.                     else
    378.                     {
    379.                         float offsetInCell = (childSize - child.sizeDelta[axis]) * alignmentOnAxis;
    380.                         SetChildAlongAxisWithScale(child, axis, pos + offsetInCell, scaleFactor);
    381.                     }
    382.                     pos += childSize * scaleFactor + spacing;
    383.                 }
    384.             }
    385.         }
    386.  
    387.         private void GetChildSizes(
    388.             RectTransform child,
    389.             int axis,
    390.             bool controlSize,
    391.             bool childForceExpand,
    392.             out float min,
    393.             out float preferred,
    394.             out float flexible)
    395.         {
    396.             if (!controlSize)
    397.             {
    398.                 min = child.sizeDelta[axis];
    399.                 preferred = min;
    400.                 flexible = 0;
    401.             }
    402.             else
    403.             {
    404.                 min = LayoutUtility.GetMinSize(child, axis);
    405.                 preferred = LayoutUtility.GetPreferredSize(child, axis);
    406.                 flexible = LayoutUtility.GetFlexibleSize(child, axis);
    407.             }
    408.  
    409.             if (childForceExpand)
    410.                 flexible = Mathf.Max(flexible, 1);
    411.         }
    412.        
    413. #if UNITY_EDITOR
    414.         protected override void Reset()
    415.         {
    416.             base.Reset();
    417.  
    418.             // For new added components we want these to be set to false,
    419.             // so that the user's sizes won't be overwritten before they
    420.             // have a chance to turn these settings off.
    421.             // However, for existing components that were added before this
    422.             // feature was introduced, we want it to be on be default for
    423.             // backwardds compatibility.
    424.             // Hence their default value is on, but we set to off in reset.
    425.             _childControlWidth = false;
    426.             _childControlHeight = false;
    427.         }
    428.  
    429.         private int __capacity = 8;
    430.         private Vector2[] __sizes = new Vector2[8];
    431.  
    432.         protected virtual void Update()
    433.         {
    434.             if (Application.isPlaying)
    435.                 return;
    436.  
    437.             int count = transform.childCount;
    438.  
    439.             if (count > __capacity)
    440.             {
    441.                 if (count > __capacity * 2)
    442.                     __capacity = count;
    443.                 else
    444.                     __capacity *= 2;
    445.  
    446.                 __sizes = new Vector2[__capacity];
    447.             }
    448.  
    449.             // If children size change in editor, update layout (case 945680 - Child GameObjects in a Horizontal/Vertical Layout Group don't display their correct position in the Editor)
    450.             bool dirty = false;
    451.             for (int i = 0; i < count; i++)
    452.             {
    453.                 RectTransform t = transform.GetChild(i) as RectTransform;
    454.                 if (t != null && t.sizeDelta != __sizes[0])
    455.                 {
    456.                     dirty = true;
    457.                     __sizes[i] = t.sizeDelta;
    458.                 }
    459.             }
    460.  
    461.             if (dirty)
    462.                 LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
    463.         }
    464.  
    465. #endif
    466.     }
    467. }
     
    easysolution likes this.
  28. cristianbobescu

    cristianbobescu

    Joined:
    Oct 21, 2019
    Posts:
    1
    In my use case, i wanted to put a text on the first line and the rest to be equally sized objects, and for that i made a vertical layout group that contains the first object that takes up a whole line(in my case, a text) and the object that contains the grid and it's elements
    Like this:
    -Vertical Layout Group:
    ....-Text
    ....-Grid
    .......-Grid element1
    ........-Grid element2
    And if you want all of it to be scrollable then you can put it all in a scroll Rect with the vertical layout group as the content.
    And the Vertical Layout group and the Grid have to have content size fitters to be able to extent if you want to have a dynamic number of elements.
     
    adityaspt likes this.