结合View.Java的源码,在draw方法中:
public void draw(Canvas canvas) {
/* View的绘制过程分为下面几步:
-
Draw the background 绘制背景
-
If necessary, save the canvas’ layers to prepare for fading 如有必要,颜色渐变淡之前保存画布层(即锁定原有的画布内容)
-
Draw view’s content 绘制View的内容
-
Draw children 绘制子View
-
If necessary, draw the fading edges and restore layers 如有必要,绘制颜色渐变淡的边框,并恢复画布(即画布改变的内容附加到原有内容上)
-
Draw decorations (scrollbars for instance) 绘制装饰,比如滚动条
*/
// Step 1, draw the background, if needed
if (!dirtyOpaque) {
drawBackground(canvas); //画背景
}
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// we're done...
return;
}
protected void dispatchDraw(Canvas canvas) {} //空实现
protected void onDraw(Canvas canvas) {} //空实现
}
ViewGroup中:
protected void dispatchDraw(Canvas canvas) {
...
drawChild(...); //绘制子view
...
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}
说明:
-
自定义一个View时,重写onDraw会绘制View。
调用View.invalidate(),会触发onDraw和computeScroll()(前提是该view被附加在当前窗口上)。
View.postInvalidate(); //UI线程调用invalidate,非UI线程调用postInvalidate
-
自定义一个ViewGroup,重写onDraw。
onDraw可能不会被调用,原因是需要先设置一个背景(颜色或图)。
表示这个ViewGroup有东西需要绘制了,才会触发draw方法,之后是onDraw方法。
因此,一般直接重写dispatchDraw来绘制ViewGroup
-
自定义一个ViewGroup
dispatchDraw会调用drawChild。