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); } } /// public sealed override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); CalcAlongAxis(0); } /// public sealed override void CalculateLayoutInputVertical() { CalcAlongAxis(1); } /// public sealed override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); } /// 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); } } } }