如何使自定义Unity LayoutGroup展开以适应内容



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

我的设置如下:

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

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

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

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

除了LayoutGroups调整大小以垂直适应其子项的缺失行为外,所有功能都如所需/预期。

我该怎么做?

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

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

主要变化:

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

最新更新