Как сделать так, чтобы пользовательская LayoutGroup Unity расширялась, чтобы соответствовать содержимому

Я пытаюсь использовать пользовательскую группу FlowLayoutGroup, как описано в ответах на этот вопрос. (также на GitHub) в ситуации, когда он должен изменить размер по вертикали, чтобы содержать его дочерние элементы.

Моя установка выглядит так:

  • ScrollableRect
    • Panel with VerticalLayoutGroup comp (content of parent scrollrect) that should resize vertically to fit children:
      • Panel with FlowLayoutGroup that should resize vertically to fit children
      • Панель с FlowLayoutGroup (2) также должна изменить размер...
      • и т.д...

Я добавил установщик размера содержимого в FlowLayoutGroup, настроил элементы управления дочерними размерами макета вертикальной группы, но безуспешно.

Пользователь может добавлять и удалять дочерние элементы групп во время работы приложения, и я хочу, чтобы пользовательский интерфейс реагировал, поэтому невозможно заранее установить высоту всего.

Я также просмотрел исходный код единства, чтобы попытаться выяснить, как написать это в компонент самостоятельно. Это выглядит лучшим выбором, но занимает много времени, так как я новичок в Unity и С#. Надеюсь, кто-то уже решал подобную проблему.

Все работает так, как хотелось/ожидалось, за исключением отсутствующего поведения изменения размера LayoutGroups, чтобы соответствовать их дочерним элементам по вертикали.

Как я могу это сделать?


person Stan    schedule 16.01.2019    source источник


Ответы (1)


Через некоторое время и значок перекати-поля я решил потратить время на поиск решения, надеюсь, кому-то еще это пригодится.

Опять же, это модифицированная версия проделанной здесь работы . Спасибо за это. Этот компонент теперь вычисляет собственный предпочтительный размер.

Основные изменения:

  1. I stripped it back quite severely:
    • All horizontal overrides are emptied, I only need the horizontal wrapping behaviour
    • Удалены некоторые очевидные переменные похмелья из класса 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;
    }
}

person Stan    schedule 03.02.2019