UGUI源码分析:LayoutSystem布局系统

   日期:2020-05-21     浏览:93    评论:0    
核心提示:系列UGUI源码分析系列总览相关前置:UGUI CanvasUpdateSystem源码分析文章目录系列UML图一览LayoutSystemLayoutRebuilder标记重建布局组件UML图一览LayoutSystemRelated Class: LayoutRebuilder、LayoutGroup、Canvas、CanvasUpdateRegistry、Related Interface: ILayoutElement、ILayoutController、ILayoutIgui

系列

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

文章目录

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

UML图一览

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图:

在下一篇文章中,作者会从LayoutGroup切入,分析布局UI的具体逻辑。

.
.
.
.
.

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

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服