android图形系统详解:Android绘制模式

泡在网上的日子 / 文 发表于2013-04-13 10:49 次阅读 Canvas,android

  当硬加速被启用,Android框架利用一个新的绘制模式来把你的应用呈现到屏幕,这个模式利用了一个显示列表.要完全理解显示列表以及它如何影响你的应用,先要理解android如何在非硬加速下绘制View.下面的小节描述了软加速的和硬加速的绘制models.
软件绘制模式

  在软件绘制模式,view按以下两步进行绘制:

   1使整个View层级都变得无效

   2绘制所有的View层级



  任何时候一个应用需要更新部分UI时,它应在任何改变了内容的View上调用invalidate()(或它的任一变体),使界面无效的消息在整个View层级中传播以计算应被绘制的屏幕区域(脏区域).之后Android系统绘任View层级中所有与脏区域有交集的View. 不幸的是,这种绘制模式有两个缺点:

   第一,这个模式需要在每个绘制路径中都执行很多代码.比如,如果你的应用在一个button上调用了invalidate()并且这个button位于另一个view之上,即使这个View没有变化,Android系统也会绘制这个View.

   第二个问题是这个绘制模式可能隐藏你应用中的bug.因为Android系统会绘制与脏区域有交集的view们,那么一个你改变了内容的view可能在没有被调用invalidate()时也会被重绘了.当这种情况发生时,你只能依赖那个需要重绘的view来获得正确的行为.但这个行为可能在你每次修改你的应用时都会改变.因此,在任何你修改了数据或状态而影响到绘制代码的时候,你总是应该在你的自定义view上调用invalidate().



  注:Androidview们会在它们的属性被改变时自动调用invalidate(),比如一个TextView的背景和文本改变时.
硬加速绘制模式

Android系统依然使用invalidate()和draw()来请求屏幕更新并画出views,但是对实际的绘制处理却不一样.现在不是在收到绘制命令立即执行了,而是Android系统把绘制命令记录到显示列表中,这个列表中包含了View层级的绘制代码的输出.另一个优化是Android系统只需为那些通过invalidate()标记为脏的View记录和更新显示列表.没有被invalidated的Views可以简单地使用先前的显示列表中的记录进行重绘.新的绘制模式包含三个阶段:

   1使整个View层级都无效

   2记录并更新显示列表

   3画显示列表



  使用此模式,你再不能依靠让View与脏区域交界而使它的draw()方法被调用.要保证Android系统记录下view的显示列表,你必须调用invalidate().忘记这样做会导致一个view总是一个模样,即使改变了它.但这是一个很容易被找出的bug.



  使用显示列表还对提升动画性能有益,因为设置了某个属性,比如alpha或rotation等,不再需invalidating目标view(自动做了).这个优化也会应用到拥有显示列表的view上(当你的应用被硬加速时的任何view).例如,假设有一个LinearLayout包含了一个ListView和一个Button,ListView位于Button之上,LinearLayout的显示列表看起来如下:

   DrawDisplayList(ListView)

   DrawDisplayList(Button)

  假设现在你想改变ListView的opacity,在调用了ListView的setAlpha(0.5f)后,显示列表现在包含如下项:

   SaveLayerAlpha(0.5)

   DrawDisplayList(ListView)

   Restore

   DrawDisplayList(Button)



ListView复杂的绘制过程没有被执行,而是仅更新了更简单的LinearLayout的显示列表.如果在一个未硬加速的应用中,列表和它爹的绘制代码都会被重新执行.
不支持的绘制操作

  当启用了硬加速,2D呈现管道会支持通用的Canvas绘制操作,也支持不常用的操作.所有的绘制操作被用来呈现widgets,layouts以及通用高级视觉效果,比如反光和平铺纹理.下面的列表描述了已知的不能被硬加速支持的绘制操作:

   Canvas

       clipPath()

       clipRegion()

       drawPicture()

       drawPosText()

       drawTextOnPath()

       drawVertices()

   Paint

       setLinearText()

       setMaskFilter()

       setRasterizer()



  另外,还有一些操作的行为在启用硬加速后会变得不一样:

   Canvas

       clipRect():异或,差异和反差异剪切都被忽略.3D变换不应用到剪切框中

       drawBitmapMesh():颜色数组被忽略

       drawLines():反锯齿不被支持

       setDrawFilter():可以设置,但被忽略

   Paint

       setDither():被忽略

       setFilterBitmap():滤镜一直启用

       setShadowLayer():仅对文本起作用

   ComposeShader

       ComposeShader只能包含不同类型的着色器(比如一个BitmapShader和一个LinearGradient,不能是两个BitmapShader)

       ComposeShader不能包含ComposeShader



  如果你的应用被这些缺少的特性或限制影响了,你可以通过调用setLayerType(View.LAYER_TYPE_SOFTWARE,null)为受影响的部分关闭硬加速.用此方法,你依然可以在其它地方享用到硬加速.

收藏 赞 (1) 踩 (0)
上一篇:android图形系统:Canvas
概述 当写一个应用时,恰当的决定你的图形需求是很重要的.不同的图形任务对应不同的技术.例如,一个静态应用的图形和动画的实现肯定与一个交互式游戏非常不同.这里,我们将讨论一些在 android 上绘制图形时的操作以及它们最适合应用的任务. Canvas 和 Dr
下一篇:对于getScrollX() 的理解
今天写了一个Scroller的demo 遇到一个问题getScrollX 这个函数获得的是什么啊? 在网上没有找到答案 我就自己写 进行测试 我在一个ViewGroup中添加图片,然后进行Scroller 实际上ViewGroup的大小是超过屏幕的大小的 所以必然会隐藏了View 那么在触摸的时候屏