190 lines
5.9 KiB
C#
190 lines
5.9 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace MeowmentDebugTool
|
|
{
|
|
/// <summary>
|
|
/// 简单的自动换行布局,用于运行时 Tab 栏。
|
|
/// </summary>
|
|
public class WrapLayoutGroup : LayoutGroup
|
|
{
|
|
[SerializeField] private float spacing = 8f;
|
|
[SerializeField] private float lineSpacing = 8f;
|
|
[SerializeField] private bool childControlWidth = false;
|
|
[SerializeField] private bool childControlHeight = false;
|
|
|
|
public float Spacing
|
|
{
|
|
get => spacing;
|
|
set => spacing = value;
|
|
}
|
|
|
|
public float LineSpacing
|
|
{
|
|
get => lineSpacing;
|
|
set => lineSpacing = value;
|
|
}
|
|
|
|
public override void CalculateLayoutInputHorizontal()
|
|
{
|
|
base.CalculateLayoutInputHorizontal();
|
|
|
|
float totalMinWidth = padding.horizontal;
|
|
float totalPreferredWidth = padding.horizontal;
|
|
|
|
for (int i = 0; i < rectChildren.Count; i++)
|
|
{
|
|
RectTransform child = rectChildren[i];
|
|
totalMinWidth += GetChildWidth(child);
|
|
totalPreferredWidth += GetChildWidth(child);
|
|
|
|
if (i < rectChildren.Count - 1)
|
|
{
|
|
totalMinWidth += spacing;
|
|
totalPreferredWidth += spacing;
|
|
}
|
|
}
|
|
|
|
SetLayoutInputForAxis(totalMinWidth, totalPreferredWidth, -1f, 0);
|
|
}
|
|
|
|
public override void CalculateLayoutInputVertical()
|
|
{
|
|
float requiredHeight = CalculateRequiredHeight(GetUsableWidth());
|
|
SetLayoutInputForAxis(requiredHeight, requiredHeight, -1f, 1);
|
|
}
|
|
|
|
public override void SetLayoutHorizontal()
|
|
{
|
|
SetChildrenAlongBothAxis();
|
|
}
|
|
|
|
public override void SetLayoutVertical()
|
|
{
|
|
SetChildrenAlongBothAxis();
|
|
}
|
|
|
|
private float GetContainerWidth()
|
|
{
|
|
float selfWidth = rectTransform.rect.width;
|
|
float parentWidth = 0f;
|
|
|
|
if (rectTransform.parent is RectTransform parentRect)
|
|
{
|
|
parentWidth = parentRect.rect.width;
|
|
if (parentWidth > 0f)
|
|
{
|
|
if (selfWidth > 0f)
|
|
{
|
|
return Mathf.Min(selfWidth, parentWidth);
|
|
}
|
|
|
|
return parentWidth;
|
|
}
|
|
}
|
|
|
|
if (selfWidth > 0f)
|
|
{
|
|
return selfWidth;
|
|
}
|
|
|
|
return float.MaxValue;
|
|
}
|
|
|
|
private float GetUsableWidth()
|
|
{
|
|
float width = GetContainerWidth() - padding.horizontal;
|
|
return width > 0f ? width : float.MaxValue;
|
|
}
|
|
|
|
private float CalculateRequiredHeight(float usableWidth)
|
|
{
|
|
if (rectChildren.Count == 0)
|
|
{
|
|
return padding.vertical;
|
|
}
|
|
|
|
float currentLineWidth = 0f;
|
|
float currentLineHeight = 0f;
|
|
float totalHeight = padding.vertical;
|
|
|
|
for (int i = 0; i < rectChildren.Count; i++)
|
|
{
|
|
RectTransform child = rectChildren[i];
|
|
float childWidth = GetChildWidth(child);
|
|
float childHeight = GetChildHeight(child);
|
|
|
|
bool needWrap = currentLineWidth > 0f && currentLineWidth + spacing + childWidth > usableWidth;
|
|
if (needWrap)
|
|
{
|
|
totalHeight += currentLineHeight + lineSpacing;
|
|
currentLineWidth = 0f;
|
|
currentLineHeight = 0f;
|
|
}
|
|
|
|
if (currentLineWidth > 0f)
|
|
{
|
|
currentLineWidth += spacing;
|
|
}
|
|
|
|
currentLineWidth += childWidth;
|
|
currentLineHeight = Mathf.Max(currentLineHeight, childHeight);
|
|
}
|
|
|
|
totalHeight += currentLineHeight;
|
|
return totalHeight;
|
|
}
|
|
|
|
private void SetChildrenAlongBothAxis()
|
|
{
|
|
float usableWidth = GetUsableWidth();
|
|
float containerRight = padding.left + usableWidth;
|
|
float x = padding.left;
|
|
float y = padding.top;
|
|
float currentLineHeight = 0f;
|
|
|
|
for (int i = 0; i < rectChildren.Count; i++)
|
|
{
|
|
RectTransform child = rectChildren[i];
|
|
float childWidth = GetChildWidth(child);
|
|
float childHeight = GetChildHeight(child);
|
|
|
|
bool needWrap = x > padding.left && x + childWidth > containerRight;
|
|
if (needWrap)
|
|
{
|
|
x = padding.left;
|
|
y += currentLineHeight + lineSpacing;
|
|
currentLineHeight = 0f;
|
|
}
|
|
|
|
SetChildAlongAxis(child, 0, x, childWidth);
|
|
SetChildAlongAxis(child, 1, y, childHeight);
|
|
|
|
x += childWidth + spacing;
|
|
currentLineHeight = Mathf.Max(currentLineHeight, childHeight);
|
|
}
|
|
}
|
|
|
|
private float GetChildWidth(RectTransform child)
|
|
{
|
|
return childControlWidth ? LayoutUtility.GetPreferredWidth(child) : GetPreferredOrRectWidth(child);
|
|
}
|
|
|
|
private float GetChildHeight(RectTransform child)
|
|
{
|
|
return childControlHeight ? LayoutUtility.GetPreferredHeight(child) : GetPreferredOrRectHeight(child);
|
|
}
|
|
|
|
private static float GetPreferredOrRectWidth(RectTransform child)
|
|
{
|
|
float preferredWidth = LayoutUtility.GetPreferredWidth(child);
|
|
return preferredWidth > 0f ? preferredWidth : child.rect.width;
|
|
}
|
|
|
|
private static float GetPreferredOrRectHeight(RectTransform child)
|
|
{
|
|
float preferredHeight = LayoutUtility.GetPreferredHeight(child);
|
|
return preferredHeight > 0f ? preferredHeight : child.rect.height;
|
|
}
|
|
}
|
|
} |