记录view的绘制顺序是因为View的绘制是叠加的,后绘制的会盖在先绘制的上边,一些特殊的界面往往需要特定的绘制顺序来实现,当然知道了顺序不知道去哪绘制也白搭。
public void draw(Canvas canvas) {
...
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 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) {
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);
drawAutofilledHighlight(canvas);
// Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
// Step 7, draw the default focus highlight
drawDefaultFocusHighlight(canvas);
if (debugDraw()) {
debugDrawFocus(canvas);
}
// we're done...
return;
}
...
}
这是View绘制的主要方法,截取draw()中的部分代码拆解后我们将关注点放在以下部分:
- drawBackground(canvas);绘制背景,⚠️私有方法不可重写。
- onDraw(canvas);绘制主体
- dispatchDraw(canvas);绘制子view
- onDrawForeground(canvas);绘制前景、滑动边缘渐变和滑动条。
在哪绘制?
- 重写draw()方法时,重绘代码写在super.draw()的上方会在绘制后才绘制背景,写在下方会在界面绘制完成后盖在上边。
- 对于剩下的三个方法重写后的绘制逻辑也一样,调用父类方法之前先绘制,之后后绘制
- 其中onDraw之后和dispatchDraw之前是同一种情况,同比类比dispatchDraw之后和onDrawForeground之前。
注意⚠️
- 如果有选择,优先使用onDraw方法。Android只会自动优化onDraw的绘制,在不需要重绘时会跳过onDraw的重复执行
- 出于效率的考虑,ViewGroup 默认会绕过 draw() 方法,去直接执行 dispatchDraw(),在我们继承ViewGroup重写dispatchDraw之外的方法时,我们需要将view的willNotDraw设置为false。当然如果父类中设置了也可以(像ScrollView一样内部设置了willNotDraw=false)
/**
* If this view doesn't do any drawing on its own, set this flag to
* allow further optimizations. By default, this flag is not set on
* View, but could be set on some View subclasses such as ViewGroup.
*
* Typically, if you override {@link #onDraw(android.graphics.Canvas)}
* you should clear this flag.
*
* @param willNotDraw whether or not this View draw on its own
*/
public void setWillNotDraw(boolean willNotDraw) {
setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}
网友评论