UGUI源码分析:LayoutSystem布局系统

系列

UGUI源码分析系列总览
相关前置:
UGUI CanvasUpdateSystem源码分析

文章目录

  • 系列
  • UML图一览
  • LayoutSystem
  • LayoutRebuilder
    • 标记
    • 重建
  • 布局组件


UML图一览

UGUI源码分析:LayoutSystem布局系统_第1张图片

LayoutSystem

Related Class: LayoutRebuilder、LayoutGroup、Canvas、CanvasUpdateRegistry、

Related Interface: ILayoutElement、ILayoutController、ILayoutIgnorer、

Intro: CanvasUpdateSystem中更新布局的具体实现系统。

  • ILayoutElement: 布局元素,布局的接收方,存储有关布局的信息
  • ILayoutController:布局控制接口,布局的实施方,制定布局规则
  • ILayoutIgnorer:忽略布局接口,忽略开关开启状态将忽略该物体的布局

LayoutSystem,是UGUI中由CanvasUpdateSystem发起(m_LayoutRebuildQueue中大部分都是LayoutRebuilder)的关于布局排列的处理系统

本文将从LayoutSystem的响应逻辑切入,并在之后的文章中结合具体的组件来分析整个LayoutSystem。


LayoutRebuilder

标记

UGUI组件(如GraphicScrollRect…)在需要布局处理时会通过标记的方式将自身RectTransform封装成一个LayoutRebuilder对象添加进CanvasUpdateSystem中的布局队列(LayoutRebuildQueue)中等待被重建。

public static void MarkLayoutForRebuild(RectTransform rect)
{
    if (rect == null || rect.gameObject == null)
        return;
    var comps = ListPool<Component>.Get();
    bool validLayoutGroup = true;
    RectTransform layoutRoot = rect;
    var parent = layoutRoot.parent as RectTransform;
    //从物体父级路径寻中寻找是否存在布局组件(ILayoutGroup)
    while (validLayoutGroup && !(parent == null || parent.gameObject == null))
    {
        validLayoutGroup = false;
        parent.GetComponents(typeof(ILayoutGroup), comps);
        for (int i = 0; i < comps.Count; ++i)
        {
            var cur = comps[i];
            if (cur != null && cur is Behaviour && ((Behaviour)cur).isActiveAndEnabled)
            {
                validLayoutGroup = true;
                layoutRoot = parent;
                break;
            }
        }
        parent = parent.parent as RectTransform;
    }
    // 检查自身是否满足布局要求
    if (layoutRoot == rect && !ValidController(layoutRoot, comps))
    {
        ListPool<Component>.Release(comps);
        return;
    }
	//添加进CanvasUpdateSystem中
    MarkLayoutRootForRebuild(layoutRoot);
    ListPool<Component>.Release(comps);
}
private static void MarkLayoutRootForRebuild(RectTransform controller)
{
    if (controller == null)
        return;
    //生成一个rebuilder对象
    var rebuilder = s_Rebuilders.Get();
    //初始化数据
    rebuilder.Initialize(controller);
    //将rebuilder对象注册进CanvasUpdate中,等待Canvas的重建命令
    if (!CanvasUpdateRegistry.TryRegisterCanvasElementForLayoutRebuild(rebuilder))
        s_Rebuilders.Release(rebuilder);
}

重建

当重建指令触发时(具体详情),LayoutRebuilder将对自身即其子级路径中的所有ILayoutElementILayoutController执行相应的接口。

//CanvasUpdateSystem触发重建
public void Rebuild(CanvasUpdate executing)
{
    switch (executing)
    {
        case CanvasUpdate.Layout:
            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;
    }
}

布局组件

经过对LayoutRebuilder的分析,布局接口的触发规则已经被摸清楚了。虽然UGUI组件中有一些组件都继承了ILayoutElement接口(例如:Image,Text,ScrollRect,InputField),但它们并不会涉及对接口方法的实现。这是因为这些组件主要是布局操作的接收方,只需要通过该接口被布局实施方所发现即可。而UGUI中负责这些接收物体的布局设置功能主要是由LayoutGroup衍生的子类组件来完成。

简单UML图:
UGUI源码分析:LayoutSystem布局系统_第2张图片
在下一篇文章中,作者会从LayoutGroup切入,分析布局UI的具体逻辑。


.
.
.
.
.


嗨,我是作者Vin129,逐儿时之梦正在游戏制作的技术海洋中漂泊。知道的越多,不知道的也越多。希望我的文章对你有所帮助:)


你可能感兴趣的:(UGUI源码分析)