首页 > Unity3D频道 > 【UGUI研究院】 > UGUI研究院之缓存策略让UI打开更快(三十)
2017
11-08

UGUI研究院之缓存策略让UI打开更快(三十)

UGUI效率不高,界面稍微复杂一点就会出现打开慢的情况,至于为什么效率不高,Unity官网或者UWA的教程都已经写的很全面了。本篇文章我不站在效率优化的角度来讲(快成型的项目其实有很度无奈),从UI缓存的角度来讲,利用缓存UI的方式来让UI打开的速度更快。灵感来自我的上一篇文章

http://www.xuanyusong.com/archives/4422

UI界面的量是很大的,例如一个MMO手游,prefab至少也得有400个以上。细心的你观察一下UI的效果图,你就会发现有很多UI元素大量的在重复出现。

比较常见的例如:

1.UI界面的底板,关闭按钮、标题、帮助按钮

2.带品质边框的图标、底图、icon、边框材质

3.按钮(可能也就是文字不一样或者大小不一样)

4.UI上显示3D模型

5.UI头像

仔细观察还会有很多这样类似的UI元素,我的缓存思路就是提前把UI元素做成模板,模板被嵌套在UI中,但是需要设置成只读,不能被使用者修改破坏原始模板的结构。

缓存池的写法就常见了,无非就是打开新界面如果出现模板元素从缓存池里取,池子里没有就创建,关闭界面再把它们放进缓存池子,这样循环的复用起来。(做到让使用者毫无感知就很方便了)

UGUI操作UI元素的4大不可抗拒的耗时,profiler里可以很清楚的看到这些耗时。

如果有缓存策略的话,关闭界面时把UI放在池子里,隐藏/显示只设置它的Layer,不要去 SetActive(false)  ,这时候耗时就只剩下SetParent了,打开界面的速度自然就会快很多了。

UGUI有个特性,如果设置某个层不被显示,需要给Canvas设置,这样这个Canvas下面的所有UI都不会被显示在屏幕上了。例如下图所示,把需要缓存的UI元素放在CacheCanvas下,CachCanvas是一个不被UICamera看到的层。

UGUI研究院之缓存策略让UI打开更快(三十) - 雨松MOMO程序研究院 - 1

OK, 原理部分已经讲完,我再讲讲一些具体的实施经验。

1.必须方便预览

使用者把自己的UIPrefab文件拖入Hierarchy视图中需要立即将所有模板预览出来,OnPreView就是预览,当然这里预览出来的prefab不能被使用者apply后重新又保存在自己UIPrefab上。(如何设置prefab嵌套 只读不可被修改 请参考我的上一篇文章)http://www.xuanyusong.com/archives/4422

2.加载缓存的策略

无非就是判断池子里有没有,没有创建一类的,SetParent 这里我就不太赘述。。

3.UI缓存的元素

可能需要给缓存UI元素绑定脚本,举个例子例如,缓存按钮,那么肯定需要提供按钮的点击事件回调。使用者可以在自己的界面类中调用里面的方法,或者监听事件。

再举个例子,比如我缓存了图标组件,但是又想加点小红点或类似的角标图,角标的图想保存在自己的prefab里,但是图标元素想用缓存的。这样运行时 setActive 父节点子节点的逻辑就一样了。

UGUI研究院之缓存策略让UI打开更快(三十) - 雨松MOMO程序研究院 - 2

还是上面的例子,我把UI元素保存在界面中,点击apply后,只有UIBox不属于这个UI界面。UIBOX和红点角标的层级可以单独调整。

UGUI研究院之缓存策略让UI打开更快(三十) - 雨松MOMO程序研究院 - 3

再给大家展示一个我们的成品UI Prefab 拖到Hierarchy后会自动展开cache部分,apply后不会被保存在UI上。嵌套的prefab也不能被使用者修改。

UGUI研究院之缓存策略让UI打开更快(三十) - 雨松MOMO程序研究院 - 4

UGUI研究院之缓存策略让UI打开更快(三十) - 雨松MOMO程序研究院 - 5

4.此法最爽的地方就是使用者几乎毫无感知缓存的存在。

每个模板都有一个路径,运行时的策略 就是  池子里有 就 setParent 到 界面模板父节点下。如果没有 就是读取prefab,实例化到hierarchy然后在setParent 到 界面模板父节点下 绑定一些代码的监听等等。

最后需要注意的是, 例如按钮这类元素,每次从池子中取出来需要添加监听,放回池子里也需要移除按钮的监听。然后就让我们的UI更快一点吧。嘿嘿,如果你有自己的意见或者想法欢迎在下面给我留言。

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

UGUI研究院之缓存策略让UI打开更快(三十)》有 19 条评论

  1. vision 说:

    学习了

  2. robertzhuang 说:

    不错啊!

  3. icetiger 说:

    不知道如果使用 canvas group 设置Alpha和Blcok Raycasts 来显示和隐藏UI 会有什么优劣?

  4. 蒙33455432 说:

    你好,我有个问题,请问怎么设置别人不可以修改呢?一直想锁定Hierarchy里的内容不被修改,找不到方法。

  5. wu fan 说:

    雨松大大,小白求问,在unity2017中使用什么触摸插件好?是用ugui自己做摇杆还是用easytouch还是有其他好办法?在线等,先谢谢了

  6. seedyan 说:

    momo你好,按照这样的ui缓存机制,确实界面切换变快了。但是对于一个后期项目,很多界面的动画都是setfalse settrue的时候执行的。这样就感觉要改茫茫多的界面动画。

  7. idzzly 说:

    如果UGUI效率不高,是不是可以考虑用NGUI,还是NGUI效率更低?求分享个Unity官网介绍这方面问题的链接,十分感谢

    • 雨松MOMO 说:

      都一样,效率都不高。 有些和UI的做法有关系,稍微不注意效率就低了。。。 随便举个例子, 比如UI上使用描边。。。。

  8. 1 说:

    关闭界面时把UI放在池子里,隐藏/显示只设置它的Layer,不要去 SetActive(false),
    只是看不见,但还是可以交互啊,还是要设置射线检测

  9. 超哥 说:

    已经在项目中实现了缓存逻辑,改了部分界面使用缓存策略,但是发现在手机上会出现部分UI无法刷新显示出来,也有部分UI明明是一帧里面执行的初始化,但是明显看得到被逐渐创建和复制的过程。很奇怪的问题。但是PC上不会又这些问题,我猜想是不是跟手机的性能有关

  10. 匿名 说:

    有几个疑问,
    1.如果一个界面有多个相同的模板出现, 不够的那还是要实例化吧, 还是直接多初始出来一些,那这些不常用的话是不是仍然常驻内存?
    2.不做在UI预设里,实际也没省去UI的实例化、SetParent、SetActive, 只是让UI预设小了一些. 但是又多了对模板的SetPosition吧?
    3.一般切换界面的速度包含CLose、Open, 那Close的时候又多了把模板摘下来放回的这一步吧?

    • 雨松MOMO 说:

      1.你说的很对, 这个就看如何去规划模板了, 举个我们游戏的例子,有一个底板 + 标题栏 + 右侧导航栏 + tab页按钮, 每个界面都是完全一样的, 并且这个模板同一时刻只会出现一次。 这种就很适合用来做模板。 (首次进游戏我就会把比较重要的某个模板预加载进来)
      2.应该只会有setParent。 模板缓存可以放在层里面, 让UI摄像机不看某个层, 这样缓存 和 取出的话 只会有setParent了。可能还有赋值。
      3.close的时候 是需要把模板摘回的操作,close 本身就比open快很多, 如果摘回的内容不多的话,其实也未必能发现卡顿。
      4.还有一种closeAndOpen的操作。
      5.模板还有个好处, 可以让模板的内容不会被别人破坏, 比如我上面举的例子,(有一个底板 + 标题栏 + 右侧导航栏 + tab页按钮,) 因为每个都是单独做的, 所以可能坐标对不齐,还有一些特定的逻辑无法统一处理。

  11. 超哥 说:

    虽然实现这样的UI缓存池不是很麻烦,但是我不确定这样到底能提高多少UI性能,同时由于使用缓存机制会给界面逻辑处理带来一些麻烦…

留下一个回复

你的email不会被公开。