UGUI最佳实践(5)-其他 UI 优化技术和技巧

本章主要包含一些有助于提高 UI 性能的建议,但是其中的一些方法可能难以维护,或者可能产生讨厌的副作用。也有一些方法是简化开发的变通方法,还有一些是解决性能问题的变通方法。

基于RectTransform的布局

Layout 组件比较昂贵,因为每次标记为dirty时,它们必须重新计算子元素的大小和位置。(详细可以参考图形重构部分)。如果给定布局中元素数量相对较少且固定,且布局结构相对简单,则可以使用基于RectTransform的布局。

通过设置 RectTransform 的锚点,RectTransform 的位置和大小能够根据父物体进行变化。例如一个两列布局,可以像下面设置锚点:

  1. 左侧一列锚点x:(0,0.5),y:(0,1)
  2. 右侧一列锚点x:(0.5,1),y:(0,1)

RectTransform 底层将会驱动位置和大小的计算,这通常要比 Layout 系统效率更高。可以通过编写代码来完成RectTransform的布局,这相对要复杂一点,不在一部分的讨论范围之内。

禁用画布

当需要显示或者隐藏部分 UI 时,通常是Enable或Disable 它的根物体,来确保所有的组件都不在接收外部消息。然而,这通常会造成画布丢弃它的VBO数据缓存,进行重构。如果经常发生这种情况,就会增加 CPU的占用,影响帧率。

一个可行的变通方案是,将需要显示或者隐藏的物体,放到画布或者子画布下面,通过Enable或Disable 画布组件来实现物体的隐藏和显示。这种方法能够控制网格的显示与否,但是会将批处理的数据保留在内存中,还有就是,UI层级的OnEnable、OnDisable事件将不会触发。

需要注意的是,这种方式只是控制网格的显示和隐藏,UI中所包含的所有脚本都不会被禁用,所以这些脚本都还会执行外部回调,比如Update。

为了避免这个问题,在制作UI时,不应该在UI脚本内直接实现 MonoBehavior 的回调,而是通过 UI 根物体上的 “Callback Manager” 来进行统一的管理,当启用或者禁用Canvas 时,可以通过控制 “Callback Manager” 来确定是否执行回调。

设置EventCamera

在WorldSpace模式和Camera模式下,为 Canvas 设置 EventCamera 或 RenderCamera 是非常重要的。通过脚本可以设置 worldCamera 属性来完成。

当EventCamera、RenderCamera没有指定时,UGUI 将会查找 MainCamera(物体标签为 MainCamera 的相机组件),这个过程中至少会调用一次 GameObject.FindWithTag 方法,该方法在执行效率上很慢,所以应该避免这种情况。

这个问题在 Overlay 模式下不会发生。

UGUI 源码定制

UGUI系统的设计已经能够支持多数使用情形,它的扩展性非常好,这也意味着在不破坏它的功能的情况下,很难对它进行优化。如果能够通过修改 UGUI 源码来提高性能,可以对源码进行重新编译并替换到Unity项目中,这个操作过程在源码库中有提到,注意,需要确保自己获取了正确版本的源码。

修改源码应该作为最后的选择方案,因为它存在一些重大的缺点。首先,必须有一个可靠的方式将编译后的Dll分配个开发组各个成员和机器;其次,每次更新Unity,必须重新进行源码合并。如果能够通过扩展现有类,或者实现自己的类来解决问题,就不要采用修改源码的方式来解决。