98 lines
3.5 KiB
C#
98 lines
3.5 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace Cryville.Common.Unity.UI {
|
|
[AddComponentMenu("Layout/Flow Layout Group")]
|
|
public class FlowLayoutGroup : LayoutGroup {
|
|
[SerializeField] Vector2 m_spacing;
|
|
public Vector2 Spacing {
|
|
get { return m_spacing; }
|
|
set { SetProperty(ref m_spacing, value); }
|
|
}
|
|
|
|
[SerializeField][Range(0, 1)] float m_itemAlignmentRatio;
|
|
public float ItemAlignmentRatio {
|
|
get { return m_itemAlignmentRatio; }
|
|
set { SetProperty(ref m_itemAlignmentRatio, value); }
|
|
}
|
|
|
|
[SerializeField][Range(0, 1)] float m_itemAlignmentStretchingRatio;
|
|
public float ItemAlignmentStretchingRatio {
|
|
get { return m_itemAlignmentStretchingRatio; }
|
|
set { SetProperty(ref m_itemAlignmentStretchingRatio, value); }
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public sealed override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); CalcAlongAxis(0); }
|
|
/// <inheritdoc />
|
|
public sealed override void CalculateLayoutInputVertical() { CalcAlongAxis(1); }
|
|
/// <inheritdoc />
|
|
public sealed override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); }
|
|
/// <inheritdoc />
|
|
public sealed override void SetLayoutVertical() { SetChildrenAlongAxis(1); }
|
|
|
|
void CalcAlongAxis(int axis) {
|
|
if (axis == 0) {
|
|
SetLayoutInputForAxis(0, 0, 1, axis); // TODO
|
|
}
|
|
else {
|
|
float width = rectTransform.rect.width - padding.horizontal;
|
|
float x = 0, y = padding.top;
|
|
float lineHeight = 0;
|
|
for (int i = 0; i < rectChildren.Count; i++) {
|
|
RectTransform child = rectChildren[i];
|
|
float minWidth = LayoutUtility.GetMinWidth(child);
|
|
float childWidth = Math.Max(minWidth, Math.Min(width, LayoutUtility.GetPreferredWidth(child)));
|
|
float childHeight = LayoutUtility.GetPreferredHeight(child);
|
|
|
|
if (childWidth > width - x) {
|
|
x = 0;
|
|
if (i > 0) y += lineHeight + m_spacing.y;
|
|
lineHeight = 0;
|
|
}
|
|
|
|
x += childWidth + m_spacing.x;
|
|
if (childHeight > lineHeight) lineHeight = childHeight;
|
|
}
|
|
SetLayoutInputForAxis(y + lineHeight, y + lineHeight, 0, 1);
|
|
}
|
|
}
|
|
|
|
void SetChildrenAlongAxis(int axis) {
|
|
float width = rectTransform.rect.width - padding.horizontal;
|
|
float x = 0, y = padding.top;
|
|
float lineHeight = 0;
|
|
int firstItemIndexOfLine = 0;
|
|
for (int i = 0; i < rectChildren.Count; i++) {
|
|
RectTransform child = rectChildren[i];
|
|
float minWidth = LayoutUtility.GetMinWidth(child);
|
|
float childWidth = Math.Max(minWidth, Math.Min(width, LayoutUtility.GetPreferredWidth(child)));
|
|
float childHeight = LayoutUtility.GetPreferredHeight(child);
|
|
|
|
if (childWidth > width - x) {
|
|
AlignItemsInLine(firstItemIndexOfLine, i, y, lineHeight);
|
|
x = 0;
|
|
if (i > 0) y += lineHeight + m_spacing.y;
|
|
lineHeight = 0;
|
|
firstItemIndexOfLine = i;
|
|
}
|
|
|
|
SetChildAlongAxis(child, 0, x + padding.left, childWidth);
|
|
SetChildAlongAxis(child, 1, y, childHeight);
|
|
|
|
x += childWidth + m_spacing.x;
|
|
if (childHeight > lineHeight) lineHeight = childHeight;
|
|
}
|
|
AlignItemsInLine(firstItemIndexOfLine, rectChildren.Count, y, lineHeight);
|
|
}
|
|
void AlignItemsInLine(int startIndex, int endIndex, float y, float lineHeight) {
|
|
for (int i = startIndex; i < endIndex; i++) {
|
|
RectTransform child = rectChildren[i];
|
|
float childHeight = LayoutUtility.GetPreferredHeight(child) * (1 - m_itemAlignmentStretchingRatio) + lineHeight * m_itemAlignmentStretchingRatio;
|
|
SetChildAlongAxis(child, 1, y + (lineHeight - childHeight) * m_itemAlignmentRatio, childHeight);
|
|
}
|
|
}
|
|
}
|
|
}
|