UGUI内核大探究(七)Graphic中我们讲到Graphic组件SetLayoutDirty里会通知LayoutRebuilder布局需要重建,那么布局是具体是怎样重建的呢?我们知道UGUI有三种布局组,HorizontalLayoutGroup(水平布局组)、VerticalLayoutGroup(垂直布局组)和GridLayoutGroup(格子布局组),为对象添加某一种布局组,就可以让其子对象按照对应布局方法排列。那么这些LayoutGroup与Graphic又有什么关系呢?本文就带着这些问题就探究一下Layout系列组件的原理。
按照惯例,附上UGUI源码下载地址。
在研究Layout系列组件之前,我们首先要看一下LayoutRebuilder这个类。Graphic是通过MarkLayoutForRebuild这个静态方法标记自己需要重建的。
public static void MarkLayoutForRebuild(RectTransform rect)
{
if (rect == null)
return;
RectTransform layoutRoot = rect;
while (true)
{
var parent = layoutRoot.parent as RectTransform;
if (!ValidLayoutGroup(parent))
break;
layoutRoot = parent;
}
// We know the layout root is valid if it's not the same as the rect,
// since we checked that above. But if they're the same we still need to check.
if (layoutRoot == rect && !ValidController(layoutRoot))
return;
MarkLayoutRootForRebuild(layoutRoot);
}
这个方法里,会找到父对象中最上层的 ILayoutGroup类型的组件(ValidLayoutGroup)layoutRoot,如果没有找到,便判断一下自己是否是ILayoutController类型(ValidController),然后为符合条件的layoutRoot创建Rebuilder。
private static void MarkLayoutRootForRebuild(RectTransform controller)
{
if (controller == null)
return;
var rebuilder = s_Rebuilders.Get();
rebuilder.Initialize(controller);
if (!CanvasUpdateRegistry.TryRegisterCanvasElementForLayoutRebuild(rebuilder))
s_Rebuilders.Release(rebuilder);
}
s_Rebuilders是一个LayoutRebuilder类型的ObjectPool,通过Get方法创建(或从Pool里取出)一个实例rebuilder(再通过Release方法回收这一段内存)。我们看到这段代码调用了TryRegisterCanvasElementForLayoutRebuild,将rebuilder注册到CanvasUpdateRegistry。
LayoutRebuilder继承了ICanvasElement接口。UGUI内核大探究(六)CanvasUpdateRegistry中介绍过当Canvas绘制前会调用CanvasUpdateRegistry,而后者会遍历所有注册到它的ICanvasElement类型的组件,调用他们的Rebuild方法。
public void Rebuild(CanvasUpdate executing)
{
switch (executing)
{
case CanvasUpdate.Layout:
// It's unfortunate that we'll perform the same GetComponents querys for the tree 2 times,
// but each tree have to be fully iterated before going to the next action,
// so reusing the results would entail storing results in a Dictionary or similar,
// which is probably a bigger overhead than performing GetComponents multiple times.
PerformLayoutCalculation(m_ToRebuild, e => (e as ILayoutElement).CalculateLayoutInputHorizontal());
PerformLayoutControl(m_ToRebuild, e => (e as ILayoutController).SetLayoutHorizontal());
PerformLayoutCalculation(m_ToRebuild, e => (e as ILayoutElement).CalculateLayoutInputVertical());
PerformLayoutControl(m_ToRebuild, e => (e as ILayoutController).SetLayoutVertical());
break;
}
}
PerformLayoutCalculation从m_ToRebuild(也就是保存在rebuilder里的layoutRo

本文探究Unity3D的UGUI系统中Layout的重建过程,重点讨论HorizontalLayoutGroup、VerticalLayoutGroup、GridLayoutGroup的工作原理,以及它们与Graphic组件的关系。通过LayoutRebuilder、ILayoutController和ILayoutGroup接口,分析了ContentSizeFitter和AspectRatioFitter如何影响对象尺寸,并揭示了LayoutGroup子类如何布局子对象。
最低0.47元/天 解锁文章
521

被折叠的 条评论
为什么被折叠?



