UGUI源码剖析(CanvasUpdateSystem 画布刷新系统)

Runtime类图分析

 

CanvasUpdateRegistry

管理着两个队列:

private readonly IndexedSet<ICanvasElement> m_LayoutRebuildQueue = new IndexedSet<ICanvasElement>();

private readonly IndexedSet<ICanvasElement> m_GraphicRebuildQueue = new IndexedSet<ICanvasElement>();

m_LayoutRebuildQueue是通过RegisterCanvasElementForLayoutRebuild

TryRegisterCanvasElementForLayoutRebuild方法添加元素。

m_GraphicRebuildQueue是通过RegisterCanvasElementForGraphicRebuild

TryRegisterCanvasElementForGraphicRebuild方法添加元素。

二者通过UnRegisterCanvasElementForRebuild移除注册元素。

在构造函数中向Canvas的willRenderCanvases 事件注册了更新函数(PerformUpdate),以用来响应重建。

Canvas.willRenderCanvases += PerformUpdate;


Canvas在渲染前会调用willRenderCanvases,即执行PerformUpdate ,方法如下:

        private void PerformUpdate()
        {
            UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Layout);
            CleanInvalidItems();

            m_PerformingLayoutUpdate = true;

            m_LayoutRebuildQueue.Sort(s_SortLayoutFunction);
            for (int i = 0; i <= (int)CanvasUpdate.PostLayout; i++)
            {
                for (int j = 0; j < m_LayoutRebuildQueue.Count; j++)
                {
                    var rebuild = instance.m_LayoutRebuildQueue[j];
                    try
                    {
                        if (ObjectValidForUpdate(rebuild))
                            rebuild.Rebuild((CanvasUpdate)i);
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e, rebuild.transform);
                    }
                }
            }

            for (int i = 0; i < m_LayoutRebuildQueue.Count; ++i)
                m_LayoutRebuildQueue[i].LayoutComplete();

            instance.m_LayoutRebuildQueue.Clear();
            m_PerformingLayoutUpdate = false;

            // now layout is complete do culling...
            ClipperRegistry.instance.Cull();

            m_PerformingGraphicUpdate = true;
            for (var i = (int)CanvasUpdate.PreRender; i < (int)CanvasUpdate.MaxUpdateValue; i++)
            {
                for (var k = 0; k < instance.m_GraphicRebuildQueue.Count; k++)
                {
                    try
                    {
                        var element = instance.m_GraphicRebuildQueue[k];
                        if (ObjectValidForUpdate(element))
                            element.Rebuild((CanvasUpdate)i);
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e, instance.m_GraphicRebuildQueue[k].transform);
                    }
                }
            }

            for (int i = 0; i < m_GraphicRebuildQueue.Count; ++i)
                m_GraphicRebuildQueue[i].GraphicUpdateComplete();

            instance.m_GraphicRebuildQueue.Clear();
            m_PerformingGraphicUpdate = false;
            UISystemProfilerApi.EndSample(UISystemProfilerApi.SampleType.Layout);
        }

流程如下:

首先调用 CleanInvalidItems删除不可用(为null或者IsDestroyed)的元素。


布局更新开始设置标识位m_PerformingLayoutUpdate为true。


对m_LayoutRebuildQueue依据父对象的数量进行排序:m_LayoutRebuildQueue.Sort(s_SortLayoutFunction)。


分别以PreLayout,Layout,PostLayout的参数顺序调用每一个元素的Rebuild方法。

其中在Rebuild之前需要判断这个元素是否有效(不为空且为Unity的Object类型)。


调用所有元素的LayoutComplete方法。
清除布局重建序列中的所有元素m_LayoutRebuildQueue.Clear()。
布局更新结束设置标志位m_PerformingLayoutUpdate = false。


完成布局后,调用组件的修剪方法ClipperRegistry.instance.Cull()。

图形更新开始设置标识位m_PerformingGraphicUpdate为true。


以PreRender,LatePreRender,MaxUpdateValue的参数顺序调用每一个元素的Rebulid方法。

其中在Rebuild之前需要判断这个元素是否有效(不为空且为Unity的Object类型)。


调用所有元素的GraphicUpdateComplete方法。
清除图形重建序列中的所有元素m_GraphicRebuildQueue.Clear()。
图形更新结束设置标志位m_PerformingGraphicUpdate = false。

CanvasUpdate

定义重建时的优先级顺序:

    public enum CanvasUpdate
    {
        /// <summary>
        /// Called before layout.
        /// </summary>
        Prelayout = 0,
        /// <summary>
        /// Called for layout.
        /// </summary>
        Layout = 1,
        /// <summary>
        /// Called after layout.
        /// </summary>
        PostLayout = 2,
        /// <summary>
        /// Called before rendering.
        /// </summary>
        PreRender = 3,
        /// <summary>
        /// Called late, before render.
        /// </summary>
        LatePreRender = 4,
        /// <summary>
        /// Max enum value. Always last.
        /// </summary>
        MaxUpdateValue = 5
    }

ICanvasElement

需要在Canvas绘制更新调用前重建的元素接口。

    /// <summary>
    /// This is an element that can live on a Canvas.
    /// </summary>
    public interface ICanvasElement
    {
        /// <summary>
        /// Rebuild the element for the given stage.
        /// </summary>
        /// <param name="executing">The current CanvasUpdate stage being rebuild.</param>
        void Rebuild(CanvasUpdate executing);

        /// <summary>
        /// Get the transform associated with the ICanvasElement.
        /// </summary>
        Transform transform { get; }

        /// <summary>
        /// Callback sent when this ICanvasElement has completed layout.
        /// </summary>
        void LayoutComplete();

        /// <summary>
        /// Callback sent when this ICanvasElement has completed Graphic rebuild.
        /// </summary>
        void GraphicUpdateComplete();

        /// <summary>
        /// Used if the native representation has been destroyed.
        /// </summary>
        /// <returns>Return true if the element is considered destroyed.</returns>
        bool IsDestroyed();
    }

Rebuild实际的重建方法。

LayoutComplete在布局重建完成后回调。

GraphicUpdateComplete在图形重建完成后回调。

IsDestroyed判断当前元素是否已经不需要参与重建了。

ClipperRegistry

内部维护着一个IClipper接口的列表

 readonly IndexedSet<IClipper> m_Clippers = new IndexedSet<IClipper>();

提供Register方法加入一个IClipper到此列表中,

Unregister移除m_Clippers 列表中的指定IClipper,

在Cull方法中遍历此列表,分别调用它们的PerformClipping方法。

脏标记


标记延迟执行,优化重新渲染的手段。

详情请见:游戏设计模式:https://gpp.tkchu.me/dirty-flag.html

例如在Graphic 中存在三种脏标分别代表三种等待重建。

尺寸改变时(RectTransformDimensions):LayoutRebuild 布局重建;
尺寸、颜色改变时:Vertices to GraphicRebuild 图像重建;
材质改变时:Material to GraphicRebuild 图像重建。

层级改变(OnTransformParentChanged)、应用动画属性(OnDidApplyAnimationProperties) :All to Rebuild 重建所有,包括布局重建和图像重建。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ui系统是一种用于游戏或应用程序中创建用户界面的工具。在Unity中,UGUI(Unity GUI)是一款强大易用的ui系统,它为开发者提供了创建和管理游戏中各种ui元素的功能。 使用UGUI可以轻松地创建按钮、文本、图像、滑块等各种ui元素,并对它们进行定位、调整大小和其他视觉效果。与其他ui系统相比,UGUI提供了更直观的工作流程和更丰富的控件库,使得开发人员能够快速构建复杂的用户界面。 学习UGUI的最好方法之一是通过阅读Unity的官方文档和教程。官方文档详细介绍了UGUI的核心概念、基本用法和常见技巧。同时,Unity官方还提供了许多示例项目和视频教程,帮助开发者理解和掌握UGUI的各种功能和用法。 除了官方文档和教程,还有许多优秀的第三方教程和资源可供学习。可以在社区论坛、博客和YouTube上找到许多教程,介绍了UGUI的高级特性、最佳实践和优化技巧。 实践和练习也是学习UGUI的关键。通过尝试创建各种ui元素,调整它们的属性和外观,以及与交互事件的配合使用,可以逐渐熟悉UGUI的使用方式和功能。同时,通过参与实际项目或练习项目,可以应用所学的知识并迅速提高技能。 总之,学习UGUI需要通过阅读文档、教程和参与实际项目的实践来逐渐掌握。通过不断练习和尝试,你可以轻松掌握Unity的UGUI系统,并使用它创建出令人满意的用户界面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值