Android View绘制顺序

记录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);
}

参考自:HenCoder自定义View绘制顺序

你可能感兴趣的:(Android View绘制顺序)