Reputation: 908
I have a panel with GridLayoutGroup
on it.
Constraint is set to "Flexible" so it is not fixed in row and column and i don't want it to be.
Now I want get the column count for this GridLayout
in code behind, and then change the size of cells to fit on screen.
GridLayoutGroup layoutgroup;
I have the GridLayoutGroup variable in my code, but there is no function to get columns of it.
how do I do this?
Upvotes: 4
Views: 7887
Reputation: 125455
You have to count them manually in a loop. You can get the column and row count from the GridLayoutGroup
component by doing the following:
1. Get the position of the first child of the Object under the GridLayoutGroup
object. The position should be from RectTransform.anchoredPosition
which returns Vector2
.
2. Loop from the second child to the rest of the child objects of the GridLayoutGroup
.
3. In each loop from #2, compare the x
component from the first child against the x
component from the current loop.
Create a boolean variable outside the loop that determines when to stop counting the row. The default value should be false
.
If the x
values match, it's a column, so increment column by 1
then set the boolean variable to true
.
If the x
values are not the same, and the boolean variable is false
, it's a row, so increment row by 1
.
Basically, you stop counting or incrementing row when column is found in the loop. That's what the boolean variable is used for.
void GetColumnAndRow(GridLayoutGroup glg, out int column, out int row)
{
column = 0;
row = 0;
if (glg.transform.childCount == 0)
return;
//Column and row are now 1
column = 1;
row = 1;
//Get the first child GameObject of the GridLayoutGroup
RectTransform firstChildObj = glg.transform.
GetChild(0).GetComponent<RectTransform>();
Vector2 firstChildPos = firstChildObj.anchoredPosition;
bool stopCountingRow = false;
//Loop through the rest of the child object
for (int i = 1; i < glg.transform.childCount; i++)
{
//Get the next child
RectTransform currentChildObj = glg.transform.
GetChild(i).GetComponent<RectTransform>();
Vector2 currentChildPos = currentChildObj.anchoredPosition;
//if first child.x == otherchild.x, it is a column, ele it's a row
if (firstChildPos.x == currentChildPos.x)
{
column++;
//Stop couting row once we find column
stopCountingRow = true;
}
else
{
if (!stopCountingRow)
row++;
}
}
}
Usage:
public GridLayoutGroup gridLG;
void Update()
{
int column = 0;
int row = 0;
GetColumnAndRow(gridLG, out column, out row);
Debug.Log("Column: " + column + " Row: " + row);
}
Upvotes: 3
Reputation: 887
Depending on when you're calling this in the lifecycle, this approach may not work. At Awake
time, all the child positions seem to still be 0,0.
Another solution is to just do the fitting math, which is a little more complicated because you need to consider both the cell width and the spacing between cells.
int GetColumnCount(GridLayoutGroup grid) {
// If 1 or 0 children, that's our column width.
if (grid.transform.childCount <= 1) return grid.transform.childCount;
// Use cell size and spacing to find the wrapping point and return the previous index.
float maxWidth = grid.GetComponent<RectTransform>().rect.width;
float cellWidth = grid.cellSize.x;
float cellSpacing = grid.spacing.x;
for (int i = 2; i < grid.transform.childCount; ++i) {
if (i * cellWidth + (i - 1) * cellSpacing > maxWidth) {
return i - 1;
}
}
// All cells fit, so just return the number of children.
return grid.transform.childCount;
}
This can be modified slightly to count rows and can be simplified if you have no spacing.
Upvotes: 0
Reputation: 7475
Actually, you don't have to iterate through all the children. Finding the rightmost element of the first row will be enough.
Usage example:
var grid = GetComponent<GridLayoutGroup>();
Vector2Int size = grid.Size();
Helper class:
using System;
using UnityEngine;
using UnityEngine.UI;
public static class GridLayoutGroupHelper
{
public static Vector2Int Size(this GridLayoutGroup grid)
{
int itemsCount = grid.transform.childCount;
Vector2Int size = Vector2Int.zero;
if (itemsCount == 0)
return size;
switch (grid.constraint)
{
case GridLayoutGroup.Constraint.FixedColumnCount:
size.x = grid.constraintCount;
size.y = getAnotherAxisCount(itemsCount, size.x);
break;
case GridLayoutGroup.Constraint.FixedRowCount:
size.y = grid.constraintCount;
size.x = getAnotherAxisCount(itemsCount, size.y);
break;
case GridLayoutGroup.Constraint.Flexible:
size = flexibleSize(grid);
break;
default:
throw new ArgumentOutOfRangeException($"Unexpected constraint: {grid.constraint}");
}
return size;
}
private static Vector2Int flexibleSize(this GridLayoutGroup grid)
{
int itemsCount = grid.transform.childCount;
float prevX = float.NegativeInfinity;
int xCount = 0;
for (int i = 0; i < itemsCount; i++)
{
Vector2 pos = ((RectTransform)grid.transform.GetChild(i)).anchoredPosition;
if (pos.x <= prevX)
break;
prevX = pos.x;
xCount++;
}
int yCount = getAnotherAxisCount(itemsCount, xCount);
return new Vector2Int(xCount, yCount);
}
private static int getAnotherAxisCount(int totalCount, int axisCount)
{
return totalCount / axisCount + Mathf.Min(1, totalCount % axisCount);
}
}
Upvotes: 4
Reputation: 1
You can also do it with localPosition of the children.
void CountColumnsAndRow()
{
Vector3 firstElementPosition = m_UpgradePanel.transform.GetChild(0).localPosition;
foreach(Transform t in m_UpgradePanel.transform)
{
if (Mathf.Approximately(firstElementPosition.y, t.localPosition.y))
m_NumOfCol++;
else break;
}
m_NumOfRow = 1;
foreach (Transform t in m_UpgradePanel.transform)
{
if(!Mathf.Approximately(firstElementPosition.y, t.localPosition.y))
{
m_NumOfRow++;
firstElementPosition = t.localPosition;
}
}
Debug.Log("RowNumber:" + m_NumOfRow + " ColumnNumber:" + m_NumOfCol);
}
Upvotes: 0