這篇博客主要爲大家介紹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類