一、前期知识储备
这个问题实际上是来自猎豹的一道Android面试题,题中实际包含了两层含义:
①requestLayout()和onLayout()的区别和联系?
②onDraw()和drawChild()的区别和联系?
二、四个方法两两之间的区别
首先,上官方文档,掌握上述四个方法的定义:
由官方文档,我们可知,调用requestLayout()方法的时机是:当前View发生了一些改变,这个改变使得现有的View失效,所以调用requestLayout()方法对View树进行重新布局,过程包括了measure()和layout()过程,但不会调用draw()过程,即不会发生重新绘制视图过程。
由官方文档,我们可知,调用onLayout()的时机是:View需要给自己设置大小和位置了或者ViewGroup需要给子View和ViewGroup自身时调用。
读者看完之后,就应该发现,其实两个方法之间的联系很少,调用时机不同,调用者不同,调用时处理的方式和结果都不同。
————————————————————我是分割线—————————————————————
onDraw()方法,View的绘制流程一共包括三步:①测量measure;②布局layout;③绘制draw;onDraw()方法就是在第三布绘制时发生,开发者已经测量好View的大小,设置好View的布局,剩下最后一步就是,具体画出这个布局。画的方法就是onDraw(),每个View都需要利用这个方法画出自己,ViewGroup除非设置了背景,否则不用调用该方法。有兴趣的读者可具体参考笔者的《View绘制流程—自定义View相关》
drawChild()方法的相关介绍,笔者还暂未在官方文档中找到,读者可以尝试查找。
参考网址:https://developer.android.google.cn/index.html
这幅图是Android硬件加速的方法调用图,笔者从其中截取了一部分,其中很清晰的展示了onDraw()方法和drawChild()方法之间的联系:
1)自定义一个view时,重写onDraw()。
调用view.invalidate(),会触发onDraw()和computeScroll()。前提是该view被附加在当前窗口上
view.postInvalidate(); //是在非UI线程上调用的
2)自定义一个ViewGroup,重写onDraw。
onDraw()方法在ViewGroup中正如前文所说,可能不会被调用,原因是需要先设置一个背景(颜色或图)。表示这个group有东西需要绘制了,才会触发draw,之后是onDraw()。
因此,一般直接重写dispatchDraw()来绘制viewGroup
3)自定义一个ViewGroup
dispatchDraw()会调用drawChild()。
小结:①绘制VIew本身的内容,通过调用View.onDraw(canvas)函数实现;
②ViewGroup绘制自己的孩子通过dispatchDraw(canvas)实现,这个方法中调用drawChild()。
上代码:
//ViewGroup中:
protected void dispatchDraw(Canvas canvas) {
...
drawChild(...); //绘制子view
...
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}
对dispatchDraw()方法感兴趣的读者,可参考这篇文章《Android中dispatchDraw分析》