Как сделать так, чтобы пользовательская Unity LayoutGroup расширялась, чтобы соответствовать содержимому - PullRequest
0 голосов
/ 17 января 2019

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

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

  • ScrollableRect
    • Панель с компоновкой VerticalLayoutGroup (содержимое родительской прокрутки), размер которой должен изменяться по вертикали, чтобы соответствовать дочерним элементам:
      • Панель с FlowLayoutGroup, размеры которой должны изменяться по вертикали, чтобы соответствовать детям
      • Панель с FlowLayoutGroup (2) также должна изменить размер ...
      • и т.д ...

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

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

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

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

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

1 Ответ

0 голосов
/ 04 февраля 2019

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

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

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

  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;
    }
}

...