View绘制之draw过程

这篇博客主要为大家介绍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类

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章