【Android】View绘制过程分析之draw

续前文“【Android】View绘制过程分析之layout",继续分析View的绘制过程。

本文分析第3阶段,分析过程的注释标记在以下代码中。

/**
 * 绘制过程
 */
public void draw(Canvas canvas) {
    if (mClipBounds != null) {
        canvas.clipRect(mClipBounds);
    }
    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;

    /*
     * 绘制过程依次进行下面的6步处理:
     *      1. 绘制背景
     *      2. If necessary, save the canvas' layers to prepare for fading
     *      3. 绘制View的内容, 在onDraw(canvas)方法中完成
     *      4. 绘制子View的内容
     *      5. If necessary, draw the fading edges and restore layers
     *      6. 绘制装饰品(如滚动条)
     */

    // 第1步,绘制背景
    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);
            }
        }
    }

    // 一般情况下,会跳过第2步与第5步
    final int viewFlags = mViewFlags;
    boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
    boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
    if (!verticalEdges && !horizontalEdges) {
        // 第3步,绘制View的内容,自定义View时,这个方法需要我们去实现。
        if (!dirtyOpaque) onDraw(canvas);

        // 第4步,绘制子View的内容,参考ViewGroup中dispatchDraw(canvas)方法的实现,
        //OK,你猜到了!又是一次遍历子View的过程,子View再调用draw(canvas)方法绘制自己及孙View。
        //父View与子View这样的遍历过程,是Android一贯的做法。
        dispatchDraw(canvas);

        // 第6步,绘制装饰品(如滚动条)
        onDrawScrollBars(canvas);

        if (mOverlay != null && !mOverlay.isEmpty()) {
            mOverlay.getOverlayView().dispatchDraw(canvas);
        }
        return;
    }
}

/**
 * 绘制View的内容,在View类此方法空实现。但在自定义View类时,要实现此方法。
 * 在这个方法中,可做的事情就多了,Canvas提供了丰富的绘图方法,关键是灵活运用!
 * 通常,你还可以通过调用以下方法或protected属性获取到一次绘制时需要用到的数值:
 * getMeasuredWidth()与getMeasuredHeight()  获取measure()中计算到的宽度与高度
 *  mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom, mScrollX, mScrollY等等,直接使用。
 */
protected void onDraw(Canvas canvas) {
}

/**
 * 下面看一下ImageView的绘制:
 */
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    if (mDrawable == null) {
        return; // couldn't resolve the URI
    }

    if (mDrawableWidth == 0 || mDrawableHeight == 0) {
        return;     // nothing to draw (empty bounds)
    }

    if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
        mDrawable.draw(canvas);
    } else {
        int saveCount = canvas.getSaveCount();
        canvas.save();
        
        if (mCropToPadding) {
            final int scrollX = mScrollX;
            final int scrollY = mScrollY;
            canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
                    scrollX + mRight - mLeft - mPaddingRight,
                    scrollY + mBottom - mTop - mPaddingBottom);
        }
        
        canvas.translate(mPaddingLeft, mPaddingTop);

        if (mDrawMatrix != null) {
            canvas.concat(mDrawMatrix);
        }
        mDrawable.draw(canvas);
        canvas.restoreToCount(saveCount);
    }
}        
    

@容新华技术博客 - http://blog.csdn.net/rongxinhua - 原创文章,转载请注明出处


你可能感兴趣的:(Android)