using UnityEngine; using UnityEngine.UI; namespace MeowmentDebugTool { /// /// 简单的自动换行布局,用于运行时 Tab 栏。 /// 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; } } }