这篇博客主要为大家介绍View绘制过程的最后一步,draw的过程。下面一张流程图为大家展示一下:
下面这段是draw()方法的源代码:
/**
* 手动的给View(和所有它的子View)制定的Canvas.在这个方法被调用之前这个View必须已经
* 做了一个完整的布局。当重新绘制一个View,重载onDraw()方法代替重载这个方法。如果你要
* 重载这个方法,先调用父View的这个方法
*
* Manually render this view (and all of its children) to the given Canvas.
* The view must have already done a full layout before this function is
* called. When implementing a view, implement
* {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.
* If you do need to override this method, call the superclass version.
*
* @param canvas The Canvas to which the View is rendered.
*/
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;
/*
* Draw必须在合适的顺序下遍历执行下面的几个drawing步骤
*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* //绘制背景
* 1. Draw the background
*
* //如果有必要,为fading去保存这个canvas的图层
* 2. If necessary, save the canvas' layers to prepare for fading
*
* //绘制View的内容
* 3. Draw view's content
*
* //绘制子View
* 4. Draw children
*
* //如果有必要,绘制fading边框和恢复图层
* 5. If necessary, draw the fading edges and restore layers
*
* //绘制装饰(滚动条)
* 6. Draw decorations (scrollbars for instance)
*/
// Step 1, draw the background, if needed
int saveCount;
if (!dirtyOpaque) {
final Drawable background = mBackground;
if (background != null) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
if (mBackgroundSizeChanged) {
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged = false;
}
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}
// 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
//绘制子View
dispatchDraw(canvas);
// Step 6, draw decorations (scrollbars)
//绘制滚动条
onDrawScrollBars(canvas);
// we're done...
return;
}
总结:
1、View的第一步是绘制背景
/**
* 绘制它(背景)的边界包括一些其他的选择,如透明度,颜色过滤
* Draw in its bounds (set via setBounds) respecting optional effects such
* as alpha (set via setAlpha) and color filter (set via setColorFilter).
*
* @param canvas The canvas to draw into
*/
public abstract void draw(Canvas canvas);
2、绘制View本身的内容,调用的方法为onDraw(canvas)方法
/**
* 当你绘制自己的时候的实现这个方法
* Implement this to do your drawing.
*
* 用画不覆盖在你已经绘制了背景的画布上
* @param canvas the canvas on which the background will be drawn
*/
protected void onDraw(Canvas canvas) {
}
3、绘制子View的内容,dispatchDraw(canvas)
/**
* 当年绘制子View的时候这个方法会被回调,这个方法通过派生类去获得控制,在子View绘制(完成)
* 之前,自己(View)绘制完成之后。
*
* Called by draw to draw the child views. This may be overridden
* by derived classes to gain control just before its children are drawn
* (but after its own view has been drawn).
* @param canvas the canvas on which to draw the view
*/
protected void dispatchDraw(Canvas canvas) {
}
4、绘制横或竖的滚动条 ,调用onDrawScrollBars(canvas)方法实现
到这里View的整个绘制过程已经分析完毕,下一篇博客将为大家讲述绘制过程可以使用的Canvas,Paint类