绘制流程
draw() 是View绘制过程的总调度方法,整个绘制过程都在draw()方法里
public void draw(Canvas canvas) { {
drawBackground(canvas); //绘制背景,无法重写
onDraw(canvas); //绘制自身
dispatchDraw(canvas); //绘制子View
onDrawForeground(canvas); //绘制前景
}
ViewGroup 默认会绕过 draw() 方法,直接执行dispatchDraw(),来简化绘制流程,所以如果你自定义了某个ViewGroup 的子类(如LinearLayout)并且需要在它的除dispatchDraw() 以外的任何一个绘制方法内绘制内容,你可以调用View.setWillNotDraw(false) 来切换到完整的绘制流程
硬件加速
就是指把 View 中绘制的计算工作交给 GPU 来处理。
CPU把绘制的内容转换为GPU 的操作保存了下来,然后就把它交给 GPU,将 Canvas.drawXXX() 变成实际的像素这件事交给GPU处理。GPU本身比CPU更擅长于绘制的计算,硬件加速在界重绘的时候会优化绘制流程,避免一些重复操作。
硬件加速优化绘制流程
如果关闭硬件加速,Canvas绘制的内容会写进一个Bitmap,然后在渲染过程中,Bitmap的像素内容被渲染到屏幕,Canvas.drawXXX() 变成实际的像素这件事是由CPU处理的,当某个 View 调用 invalidate() 方法时,为了正确计算 Bitmap 的像素,和它相交的 View,这个 View 的父 View,甚至顶级 View都需要被调用 invalidate()来重绘。
如果开启硬件加速,绘制的内容会被转换成 GPU 的操作保存下来,相互独立,只需要把发生了改变的 View 调用 invalidate() 方法以更新它所对应的 GPU 操作就可以了,其他View不用改动
硬件加速的使用限制
Canvas 的部分方法不支持硬件加速
HardwareAccelerated.png
硬件加速的开启关闭
View.setLayerType(int layerType, @Nullable Paint paint)
参数layerType值可以为:
LAYER_TYPE_SOFTWARE:使用软件来绘制Layer,绘制到一个 Bitmap,并关闭硬件加速
LAYER_TYPE_HARDWARE:使用 GPU 来绘制Layer,绘制到一个 OpenGL texture,开启硬件加速
LAYER_TYPE_NONE:关闭Layer
setLayerType是给View设置 Layer(离屏缓冲) 的类型,作用是单独启用一块地方来绘制 View ,如果设置了 Layer ,View的绘制结果会被缓存下来,提高重绘效率
因此,在进行移动、旋转等(无需调用 invalidate())的属性动画的时候设置 Hardware Layer 可以提升动画的效率
circleProgress.setLayerType(LAYER_TYPE_HARDWARE, null);
val animator = ObjectAnimator.ofFloat(circleProgress, "rotationY", 0f, 45f)
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
circleProgress.setLayerType(LAYER_TYPE_NONE, null)
}
})
animator.start()
//或者使用ViewPropertyAnimator动画,使用withLayer()开启,这是一次性的,
//在onAnimationEnd回调里会设置回原来的LayerType
circleProgress.animate()
.rotationY(45f)
.withLayer()
LAYER_TYPE_HARDWARE_EXAMPLE.png
由于设置了 Layer ,View 在初次绘制时以及每次 invalidate() 后重绘时,需要进行两次的绘制工作(一次绘制到 Layer,一次从 Layer 绘制到显示屏),所以其实它的每次绘制的效率是被降低了的












网友评论