android图形系统详解六:View layer

时间:2023-02-06 23:38:07

View layers

  在所有版本的Android中,views都有画到离屏缓冲的能力,这包括使用view的绘制cache,或使用Canvas.saveLayer().离屏缓冲,或者说层,有很多用处.你可以使用它们来为复杂的view动画或使用组合效果时提高性能.例如,你可以使用Canvas.saveLayer()实现淡出效果,这个方法会临时的把一个view画到一个layer中然后使用一个透明系数把它组合回屏幕上.



  从Android3.0 (API level11)开始,你对何时以及如何通过View.setLayerType()方法来使用layer有了更多的控制能力.此方法有两个参数:你想使用的layer的类型和一个可选的Paint对象,这个对象描述了layer应被如何组合.你可以使用Paint参数来应用颜色过滤,或指定混合模式或不透明度到一个layerview可以使用以下三个类型之一:

  • LAYER_TYPE_NONE:view按一般方式绘制,不使用离屏缓冲.这是默认的行为.

  • LAYER_TYPE_HARDWARE:如果应用被硬加速了,view会被绘制到一个硬件纹理中.如果应用没被硬加速,此类型的layer的行为同于LAYER_TYPE_SOFTWARE

  • LAYER_TYPE_SOFTWARE:view被绘制到一个bitmap中.


  要使用哪种layer类型取决于你的目标:

  • 性能:使用一个硬件layer类型把view画到硬件纹理中.当一个view被画到一个layer中,它的绘制代码直到调用invalidate()时才会被执行.一些动画,比如透明变化的动画,可以直接在layer上应用,这对GPU来说轻而易举.

  • 视觉效果:使用硬件或软件layer类型和一个Paint将视觉特效应用到view上.比如,你可以在后台用ColorMatrixColorFilter以黑白色画一个view

  • 兼容性:使用一个软件layer类型来强制view以软件方式绘制.如果一个view是硬加速的(比如,如果你的整个应用是硬加速的),但呈现时出现问题,改用软件方式绘制是一个避开硬件呈现管道限制的最简单的方式.

View layers 和动画

  当你的应用被硬加速时,硬件layer可以提供更快更平滑的动画.当向一个有很多绘制操作的复杂的view应用动画时,要永远保证以60fps的速度运行是不可能的.但这可以通过使用硬件layersview呈现到硬件纹理中来减轻一些负担.硬件纹理之后可以被用来产生动画,避免view为了产生动画而不断的重画自己.view在其属性发生改变而调用invalidate()或你主动调用invalidate()之前不会重画,如果你正在你的应用运行动画但是并不能获得平滑的效果,那么可以考虑在你的动画view上启用硬件layer


  当一个view被硬件layer所支持,它的一些属性的处理就跟layer混合到屏幕上的方式相关了.设置这些属性的操作将变得更高效,因为它们不再导致view变得无效再重绘了.下面列出的就是这些属性,调用这些属性的设置器时会对invalidation操作产生最佳的优化并且不再重画目标view

  • alpha:改变layer的透明度

  • x, y,translationX, translationY:改变layer的位置

  • scaleX,scaleY:改变layer的大小

  • rotation,rotationX, rotationY: 在3D空间中改变layer的方向.

  • pivotX,pivotY: 改变layer的变换原点坐标.

  这些属性是在使用一个ObjectAnimatorview产生动画时使用的.如果你想操作这些属性,调用适当的settergetter即可.例如,要改变透明属性,调用setAlpha().下面的代码片段演示了让一个View绕Y轴进行三维变换的最佳方法:

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);ObjectAnimator.ofFloat(view, "rotationY", 180).start();

  因为硬件 layers使用显卡内存,所以强烈建议你只在动画期间使用它们并在动画结束后禁止它们.你可以使用动画侦听器来做到:

View.setLayerType(View.LAYER_TYPE_HARDWARE, null);ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);animator.addListener(new AnimatorListenerAdapter() {    @Override    public void onAnimationEnd(Animator animation) {        view.setLayerType(View.LAYER_TYPE_NONE, null);    }});animator.start();


提示和技巧

  切换到2D图形硬加速能立即提升性能,但是你仍然需要按照以下建议来有效使用GPU

  • 减少你应用中views的数量

      系统画的views越多,就越慢.这对软件呈现管线来说也是一样.减少views是优化你的UI的最简单的办法.

  • 避免过度绘制

      不要在彼此的上面画太多layers.移除那些完全被别的不透明view遮盖的view们.如果你需要把多个layer混合画到每个view的上面,应考虑把它们合并到一个layer中.对于当前硬件的一个好原则是画的次数不要超过每帧屏幕上像素的2.5倍(透明像素按位图计数)

  • 不要在绘制方法们中创建render对象

      一个常见的错误就是在每次调用绘制方法时都创建新的PaintPath.这强制垃圾收集器运行得更频繁,并且导致高速缓存和硬件管道优化不起作用.

  • 不要太频繁地修改shapes

      比如混合shapes,paths,circles时,是使用纹理遮罩呈现的.每次你创建或修改一个path,硬件管道都创建一个新的遮罩,这个代价是很昂贵的.

  • 不要太频繁地修改bitmap

      你每次改变一个bitmap的内容,你下次去画它时它会作为一个GPU纹理重新上载.

  • 小心使用alpha(透明度)

      当你用setAlpha()AlphaAnimation,或ObjectAnimator把一个view设为透明,它将被呈现到一个离屏缓冲中,此时就需要双倍的填充速率.当在一个very大的view上应用透明度时,应考虑把viewlayer类型设置为LAYER_TYPE_HARDWARE