213 lines
8.6 KiB
C#
213 lines
8.6 KiB
C#
|
|
using UnityEngine;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
|
||
|
|
namespace UnityEngine.UI
|
||
|
|
{
|
||
|
|
[AddComponentMenu("Layout/Auto Expand Grid Layout Group", 152)]
|
||
|
|
public class AutoExpandGridLayoutGroup : LayoutGroup
|
||
|
|
{
|
||
|
|
public enum Corner { UpperLeft = 0, UpperRight = 1, LowerLeft = 2, LowerRight = 3 }
|
||
|
|
public enum Axis { Horizontal = 0, Vertical = 1 }
|
||
|
|
public enum Constraint { Flexible = 0, FixedColumnCount = 1, FixedRowCount = 2 }
|
||
|
|
|
||
|
|
[SerializeField]
|
||
|
|
protected Corner m_StartCorner = Corner.UpperLeft;
|
||
|
|
public Corner startCorner { get { return m_StartCorner; } set { SetProperty(ref m_StartCorner, value); } }
|
||
|
|
|
||
|
|
[SerializeField]
|
||
|
|
protected Axis m_StartAxis = Axis.Horizontal;
|
||
|
|
public Axis startAxis { get { return m_StartAxis; } set { SetProperty(ref m_StartAxis, value); } }
|
||
|
|
|
||
|
|
[SerializeField]
|
||
|
|
protected Vector2 m_CellSize = new Vector2(100, 100);
|
||
|
|
public Vector2 cellSize { get { return m_CellSize; } set { SetProperty(ref m_CellSize, value); } }
|
||
|
|
|
||
|
|
[SerializeField]
|
||
|
|
protected Vector2 m_Spacing = Vector2.zero;
|
||
|
|
public Vector2 spacing { get { return m_Spacing; } set { SetProperty(ref m_Spacing, value); } }
|
||
|
|
|
||
|
|
[SerializeField]
|
||
|
|
protected Constraint m_Constraint = Constraint.Flexible;
|
||
|
|
public Constraint constraint { get { return m_Constraint; } set { SetProperty(ref m_Constraint, value); } }
|
||
|
|
|
||
|
|
[SerializeField]
|
||
|
|
protected int m_ConstraintCount = 2;
|
||
|
|
public int constraintCount { get { return m_ConstraintCount; } set { SetProperty(ref m_ConstraintCount, Mathf.Max(1, value)); } }
|
||
|
|
|
||
|
|
protected AutoExpandGridLayoutGroup()
|
||
|
|
{ }
|
||
|
|
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
protected override void OnValidate()
|
||
|
|
{
|
||
|
|
base.OnValidate();
|
||
|
|
constraintCount = constraintCount;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
public override void CalculateLayoutInputHorizontal()
|
||
|
|
{
|
||
|
|
base.CalculateLayoutInputHorizontal();
|
||
|
|
|
||
|
|
int minColumns = 0;
|
||
|
|
int preferredColumns = 0;
|
||
|
|
if (m_Constraint == Constraint.FixedColumnCount)
|
||
|
|
{
|
||
|
|
minColumns = preferredColumns = m_ConstraintCount;
|
||
|
|
}
|
||
|
|
else if (m_Constraint == Constraint.FixedRowCount)
|
||
|
|
{
|
||
|
|
minColumns = preferredColumns = Mathf.CeilToInt(rectChildren.Count / (float)m_ConstraintCount - 0.001f);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
minColumns = 1;
|
||
|
|
preferredColumns = Mathf.CeilToInt(Mathf.Sqrt(rectChildren.Count));
|
||
|
|
}
|
||
|
|
|
||
|
|
SetLayoutInputForAxis(
|
||
|
|
padding.horizontal + (cellSize.x + spacing.x) * minColumns - spacing.x,
|
||
|
|
padding.horizontal + (cellSize.x + spacing.x) * preferredColumns - spacing.x,
|
||
|
|
-1, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void CalculateLayoutInputVertical()
|
||
|
|
{
|
||
|
|
int minRows = 0;
|
||
|
|
if (m_Constraint == Constraint.FixedColumnCount)
|
||
|
|
{
|
||
|
|
minRows = Mathf.CeilToInt(rectChildren.Count / (float)m_ConstraintCount - 0.001f);
|
||
|
|
}
|
||
|
|
else if (m_Constraint == Constraint.FixedRowCount)
|
||
|
|
{
|
||
|
|
minRows = m_ConstraintCount;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
float width = rectTransform.rect.size.x;
|
||
|
|
int cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - padding.horizontal + spacing.x + 0.001f) / (cellSize.x + spacing.x)));
|
||
|
|
minRows = Mathf.CeilToInt(rectChildren.Count / (float)cellCountX);
|
||
|
|
}
|
||
|
|
|
||
|
|
float minSpace = padding.vertical + (cellSize.y + spacing.y) * minRows - spacing.y;
|
||
|
|
SetLayoutInputForAxis(minSpace, minSpace, -1, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void SetLayoutHorizontal()
|
||
|
|
{
|
||
|
|
SetCellsAlongAxis(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void SetLayoutVertical()
|
||
|
|
{
|
||
|
|
SetCellsAlongAxis(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SetCellsAlongAxis(int axis)
|
||
|
|
{
|
||
|
|
// Normally a Layout Controller should only set horizontal values when invoked for the horizontal axis
|
||
|
|
// and only vertical values when invoked for the vertical axis.
|
||
|
|
// However, in this case we set both the horizontal and vertical position when invoked for the vertical axis.
|
||
|
|
// Since we only set the horizontal position and not the size, it shouldn't affect children's layout,
|
||
|
|
// and thus shouldn't break the rule that all horizontal layout must be calculated before all vertical layout.
|
||
|
|
|
||
|
|
if (axis == 0)
|
||
|
|
{
|
||
|
|
// Only set the sizes when invoked for horizontal axis, not the positions.
|
||
|
|
for (int i = 0; i < rectChildren.Count; i++)
|
||
|
|
{
|
||
|
|
RectTransform rect = rectChildren[i];
|
||
|
|
|
||
|
|
m_Tracker.Add(this, rect,
|
||
|
|
DrivenTransformProperties.Anchors |
|
||
|
|
DrivenTransformProperties.AnchoredPosition |
|
||
|
|
DrivenTransformProperties.SizeDelta);
|
||
|
|
|
||
|
|
rect.anchorMin = Vector2.up;
|
||
|
|
rect.anchorMax = Vector2.up;
|
||
|
|
rect.sizeDelta = cellSize;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
float width = rectTransform.rect.size.x;
|
||
|
|
float height = rectTransform.rect.size.y;
|
||
|
|
|
||
|
|
int cellCountX = 1;
|
||
|
|
int cellCountY = 1;
|
||
|
|
if (m_Constraint == Constraint.FixedColumnCount)
|
||
|
|
{
|
||
|
|
cellCountX = m_ConstraintCount;
|
||
|
|
cellCountY = Mathf.CeilToInt(rectChildren.Count / (float)cellCountX - 0.001f);
|
||
|
|
}
|
||
|
|
else if (m_Constraint == Constraint.FixedRowCount)
|
||
|
|
{
|
||
|
|
cellCountY = m_ConstraintCount;
|
||
|
|
cellCountX = Mathf.CeilToInt(rectChildren.Count / (float)cellCountY - 0.001f);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (cellSize.x + spacing.x <= 0)
|
||
|
|
cellCountX = int.MaxValue;
|
||
|
|
else
|
||
|
|
cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - padding.horizontal + spacing.x + 0.001f) / (cellSize.x + spacing.x)));
|
||
|
|
|
||
|
|
if (cellSize.y + spacing.y <= 0)
|
||
|
|
cellCountY = int.MaxValue;
|
||
|
|
else
|
||
|
|
cellCountY = Mathf.Max(1, Mathf.FloorToInt((height - padding.vertical + spacing.y + 0.001f) / (cellSize.y + spacing.y)));
|
||
|
|
}
|
||
|
|
|
||
|
|
int cornerX = (int)startCorner % 2;
|
||
|
|
int cornerY = (int)startCorner / 2;
|
||
|
|
|
||
|
|
int cellsPerMainAxis, actualCellCountX, actualCellCountY;
|
||
|
|
if (startAxis == Axis.Horizontal)
|
||
|
|
{
|
||
|
|
cellsPerMainAxis = cellCountX;
|
||
|
|
actualCellCountX = Mathf.Clamp(cellCountX, 1, rectChildren.Count);
|
||
|
|
actualCellCountY = Mathf.Clamp(cellCountY, 1, Mathf.CeilToInt(rectChildren.Count / (float)cellsPerMainAxis));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
cellsPerMainAxis = cellCountY;
|
||
|
|
actualCellCountY = Mathf.Clamp(cellCountY, 1, rectChildren.Count);
|
||
|
|
actualCellCountX = Mathf.Clamp(cellCountX, 1, Mathf.CeilToInt(rectChildren.Count / (float)cellsPerMainAxis));
|
||
|
|
}
|
||
|
|
|
||
|
|
Vector2 requiredSpace = new Vector2(
|
||
|
|
actualCellCountX * cellSize.x + (actualCellCountX - 1) * spacing.x,
|
||
|
|
actualCellCountY * cellSize.y + (actualCellCountY - 1) * spacing.y
|
||
|
|
);
|
||
|
|
Vector2 startOffset = new Vector2(
|
||
|
|
GetStartOffset(0, requiredSpace.x),
|
||
|
|
GetStartOffset(1, requiredSpace.y)
|
||
|
|
);
|
||
|
|
|
||
|
|
for (int i = 0; i < rectChildren.Count; i++)
|
||
|
|
{
|
||
|
|
int positionX;
|
||
|
|
int positionY;
|
||
|
|
if (startAxis == Axis.Horizontal)
|
||
|
|
{
|
||
|
|
positionX = i % cellsPerMainAxis;
|
||
|
|
positionY = i / cellsPerMainAxis;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
positionX = i / cellsPerMainAxis;
|
||
|
|
positionY = i % cellsPerMainAxis;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cornerX == 1)
|
||
|
|
positionX = actualCellCountX - 1 - positionX;
|
||
|
|
if (cornerY == 1)
|
||
|
|
positionY = actualCellCountY - 1 - positionY;
|
||
|
|
|
||
|
|
float realsize = ((width - (spacing[0] * (actualCellCountX - 1))) / actualCellCountX);
|
||
|
|
SetChildAlongAxis(rectChildren[i], 0, startOffset.x + (realsize + spacing[0]) * positionX, realsize);
|
||
|
|
SetChildAlongAxis(rectChildren[i], 1, startOffset.y + (cellSize[1] + spacing[1]) * positionY, cellSize[1]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|