1

在需要垂直调整大小以包含其子项的情况下,我正在尝试使用此问题的答案(也在GitHub 上)中描​​述的自定义 FlowLayoutGroup。

我的设置如下所示:

  • 可滚动矩形
    • 具有应垂直调整大小以适合子级的 VerticalLayoutGroup comp(父 scrollrect 的内容)的面板:
      • 带有 FlowLayoutGroup 的面板应垂直调整大小以适合子级
      • 带有 FlowLayoutGroup (2) 的面板也必须调整大小...
      • ETC...

我在 FlowLayoutGroup 中添加了一个内容大小调整器,调整了垂直组的布局子大小控件,但没有成功。

用户可以在应用程序运行时添加和删除组的子项,我希望 UI 做出响应,因此无法提前设置所有内容的高度。

我还查看了统一源代码,试图弄清楚如何自己将其写入组件中。这看起来是最好的选择,但由于我是 Unity 和 C# 的新手,所以我花了相当多的时间。希望有人已经解决了类似的问题。

一切都按预期/预期运行,除了 LayoutGroups 调整大小以垂直适应其子项的缺失行为。

我怎样才能做到这一点?

4

1 回答 1

2

经过一段时间和风滚草徽章后,我决定花时间制定解决方案,希望其他人也能从中受益。

同样,这是此处所做工作的修改版本。感谢那。这个组件现在计算它自己的首选大小。

主要变化:

  1. 我把它剥离得很严重:
    • 所有水平覆盖都被清空,我只需要水平环绕行为
    • 从 GridLayout 类中删除了一些明显的宿醉变量
  2. 计算子位置和行数的逻辑,首选高度在它自己的方法中。
  3. 子位置存储在 Vector2 数组中,以将计算与子设置分开。

这解决了整个组件的高度没有调整的问题,它也立即响应,由于设置子 rectTransforms 的方式,原始脚本然后访问脚本需要两个“周期”来识别孩子的尺寸。

这适合我的所有需求,我想它也可以很容易地重新加工以处理垂直包装......

using UnityEngine;
using UnityEngine.UI;

[AddComponentMenu("Layout/Wrap Layout Group", 153)]
public class WrapLayoutGroup : LayoutGroup
{
    [SerializeField] protected Vector2 m_Spacing = Vector2.zero;
    public Vector2 spacing { get { return m_Spacing; } set { SetProperty(ref m_Spacing, value); } }

    [SerializeField] protected bool m_Horizontal = true;
    public bool horizontal { get { return m_Horizontal; } set { SetProperty(ref m_Horizontal, value); } }

    private float availableWidth { get { return rectTransform.rect.width - padding.horizontal + spacing.x; } }

    private const float MIN_HEIGHT = 80;

    private int preferredRows = 1;
    private float calculatedHeight = MIN_HEIGHT;

    private Vector2[] childPositions = new Vector2[0];

    protected WrapLayoutGroup()
    { }

#if UNITY_EDITOR
    protected override void OnValidate()
    {
        base.OnValidate();
    }

#endif

    public override void CalculateLayoutInputVertical()
    {
        calculatePositionsAndRequiredSize();
        SetLayoutInputForAxis(calculatedHeight, calculatedHeight, -1, 1);
    }

    public override void SetLayoutHorizontal() { }

    public override void SetLayoutVertical()
    {
        SetChildren();
    }

    private void SetChildren()
    {
        for (int i = 0; i < rectChildren.Count; i++)
        {
            RectTransform child = rectChildren[i];
            SetChildAlongAxis(child, 0, childPositions[i].x, LayoutUtility.GetPreferredWidth(child));
            SetChildAlongAxis(child, 1, childPositions[i].y, LayoutUtility.GetPreferredHeight(child));
        }
    }

    private void calculatePositionsAndRequiredSize()
    {
        childPositions = new Vector2[rectChildren.Count];

        Vector2 startOffset = new Vector2(
            GetStartOffset(0, 0),
            GetStartOffset(1, 0)
        );

        Vector2 currentOffset = new Vector2(
            startOffset.x,
            startOffset.y
        );

        float childHeight = 0;
        float childWidth = 0;
        float maxChildHeightInRow = 0;

        int currentRow = 1;

        for (int i = 0; i < rectChildren.Count; i++)
        {
            childHeight = LayoutUtility.GetPreferredHeight(rectChildren[i]);
            childWidth = LayoutUtility.GetPreferredWidth(rectChildren[i]);

            //check for new row start
            if (currentOffset.x + spacing.x + childWidth > availableWidth && i != 0)
            {
                currentOffset.x = startOffset.x;
                currentOffset.y += maxChildHeightInRow + spacing.y;
                currentRow++;
                maxChildHeightInRow = 0;
            }

            childPositions[i] = new Vector2(
                currentOffset.x,
                currentOffset.y
            );

            //update offset
            maxChildHeightInRow = Mathf.Max(maxChildHeightInRow, childHeight);
            currentOffset.x += childWidth + spacing.x;

        }

        //update groups preferred dimensions
        preferredRows = currentRow;
        calculatedHeight = currentOffset.y + maxChildHeightInRow + padding.vertical - spacing.y;
    }
}

于 2019-02-03T22:58:08.220 回答