【Android - 自定义View】之View的draw过程解析

  draw(绘制)过程的作用是将View绘制到屏幕上面。View中有 draw() 方法和 onDraw() 方法,但onDraw()方法是空方法;ViewGroup中没有draw()方法,也没有onDraw()方法。由此可以推测出:ViewGroup的绘制过程调用的流程和View的绘制过程流程是相同的,且和onLayout()、onMeasure()方法一样,因为不同的ViewGroup子类有不同的绘制方式,因此将onDraw()方法下放到ViewGroup的子类中实现。接下来看一下View类的draw()方法的源码:

/**
 * 在给定的Canvas画布上手动渲染这个View及其所有子元素;
 * 在调用这个方法之前,这个View必须已经经过了layout布局过程;
 * 在自定义View的时候,不能重写这个方法,而应该重写onDraw()方法。
 *
 * @param canvas View渲染的目标画布
 */
@CallSuper
public void draw(Canvas canvas) {
    final int privateFlags = mPrivateFlags;
    final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
            (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
    mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
    /*
     * 这种遍历绘制的方法需要执行几个步骤,且必须按适当的顺序执行
     * 1. 绘制背景
     * 2. (按需执行)保存画布层以应对褪色
     * 3. 绘制View的内容
     * 4. 绘制View中的子元素
     * 5. (按需执行)绘制褪色边缘并恢复画布层
     * 6. 绘制装饰物(前景、滚动条等)
     */
    // Step 1、绘制背景
    int saveCount;
    if (!dirtyOpaque) {
        drawBackground(canvas);
    }
    // 一般情况下,都会尽量跳过Step2和Stop5
    final int viewFlags = mViewFlags;
    boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
    boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
    if (!verticalEdges && !horizontalEdges) {
        // Step 3、绘制View中的内容
        if (!dirtyOpaque) onDraw(canvas);
        // Step 4、绘制View中的子元素
        dispatchDraw(canvas);
        // Overlay是View内容的一部分,应该画在前景的底下(先于前景绘制)
        if (mOverlay != null && !mOverlay.isEmpty()) {
            mOverlay.getOverlayView().dispatchDraw(canvas);
        }
        // Step 6、绘制装饰物,如前景、滚动条
        onDrawForeground(canvas);
        // 完成绘制
        return;
    }

    /*
     * 我们在下面做了完整的例程:
     * 这是一种不常见的情况,在这种情况中渲染速度不是很重要,因此我们将上面的一些流程又重复了一遍
     */
    // ......代码省略......
}

 

  从上面的代码可以看出,View的绘制过程总共分为六个步骤,但大多数情况下,第二步和第五步都会被省略,因此,我们在这里只分析1、3、4、6步骤。这样,View的绘制流程可以总结为: 绘制背景->绘制内容->绘制子元素->绘制其他(前景、滚动条等) ,对应的四个方法分别是: drawBackground() 、 onDraw() 、 dispatchDraw() 、 onDrawForeground() 。其中,onDraw()方法和dispatchDraw()方法在View类中没有实现,需要我们在自定义View中自行重写。

 

posted on 2017-04-17 11:02  ITGungnir  阅读(606)  评论(0编辑  收藏  举报

导航