This repository has been archived on 2025-08-02. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Cryville.EEW.Unity/Assets/Cryville.Common/Unity/UI/FlowLayoutGroup.cs
2025-02-14 16:06:00 +08:00

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);
}
}
}
}