美文网首页
View绘制流程(四) - onDraw

View绘制流程(四) - onDraw

作者: 世道无情 | 来源:发表于2019-02-12 14:27 被阅读0次

    1. onDraw


    onMeasure、onLayout结束后,就到 onDraw,这里就是 真正的绘制

    private void performDraw() {
        draw(fullRedrawNeeded);
    }
    
    private void draw(boolean fullRedrawNeeded) {
        if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
             return;
        }
    }
    
    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
                boolean scalingRequired, Rect dirty) {
    // Draw with software renderer.
            final Canvas canvas;
            try {
                final int left = dirty.left;
                final int top = dirty.top;
                final int right = dirty.right;
                final int bottom = dirty.bottom;
                
                // 创建Canvas对象
                canvas = mSurface.lockCanvas(dirty);
                // 然后调用 view的 draw
                mView.draw(canvas);
            return true;
    }
    
    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;
    
            /*
             * 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);
    
                // Step 6, draw decorations (foreground, scrollbars)
                onDrawForeground(canvas);
    
                // we're done...
                return;
            }
    
            // Step 2, save the canvas' layers
            int paddingLeft = mPaddingLeft;
    
            // Step 3, draw the content
            if (!dirtyOpaque) onDraw(canvas);
    
            // Step 4, draw the children
            dispatchDraw(canvas);
    
            // Step 5, draw the fade effect and restore layers
            final Paint p = scrollabilityCache.paint;
            final Matrix matrix = scrollabilityCache.matrix;
            final Shader fade = scrollabilityCache.shader;
    
            // Step 6, draw decorations (foreground, scrollbars)
            onDrawForeground(canvas);
        }
    
    draw绘制 用了 模板设计模式,重点是第三步

    对于第一步: 绘制该view 的背景

    if (!dirtyOpaque) {
        // Step 1, draw the background, if needed
        drawBackground(canvas);
    }
    
    private void drawBackground(Canvas canvas) {
    
           // 首先获取 Drawable 对象 - background ,这里的 background 其实就是 在 xml文件中 通过
           // android:background 设置的 背景或颜色,也可以在代码中通过
           // setBackgroundColor()、setBackgroundResource() 设置背景
           final Drawable background = mBackground;
    
            // 调用 drawable 的 draw() 绘制背景
           background.draw(canvas);
        }
    

    对于第三步: 绘制该view 的内容
    绘制内容调用 onDraw,这个onDraw是一个空方法,是因为 每个view的 内容 肯定不同,所以 绘制内容让 子类 实现;

    // Step 3, draw the content
    if (!dirtyOpaque) onDraw(canvas);
    
    protected void onDraw(Canvas canvas) {
    }
    

    对于第四步:绘制当前view的 所有的子view

    // Step 4, draw the children
    dispatchDraw(canvas);
    
    protected void dispatchDraw(Canvas canvas) {
    }
    

    如果当前 view 没有 子view,就不需要绘制, View源码中的 dispatchDraw是空的,而ViewGroup中的 dispatchDraw 有具体的绘制代码;
    对于第六步:绘制该view的 滚动条

    // Step 6, draw decorations (foreground, scrollbars)
    onDrawForeground(canvas);
    

    2. 示例代码


    下边通过一个示例代码,演示:创建画笔Paint,在 画布Canvas 绘制矩形、绘制TextView文字

    效果图:
    图片.png
    1>:自定义MyView :
    /**
     * ================================================
     * Email: 2185134304@qq.com
     * Created by Novate 2018/12/25 16:33
     * Version 1.0
     * Params:
     * Description:    自定义MyView,继承View,
     * 
     *      备注:用于演示:用画笔在画布上边画矩形、画文字
     * ================================================
    */
    
    public class MyView extends View {
    
        private Paint mPaint ;
    
        public MyView(Context context) {
            this(context,null);
        }
    
        public MyView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs , 0);
        }
    
        public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            // 创建画笔对象
            mPaint = new Paint() ;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 设置画笔颜色为黄色
            mPaint.setColor(Color.YELLOW);
            // 在画布上画矩形
            canvas.drawRect(0 , 0 , getWidth() , getHeight() , mPaint);
    
            // 设置画笔颜色为蓝色
            mPaint.setColor(Color.BLUE);
            mPaint.setTextSize(20);
            String text = "殷桃" ;
            // 在画布上写文字
            canvas.drawText(text , 0 , getHeight()/2 , mPaint);
        }
    }
    
    2>:在 xml中使用:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.novate.test.view.MyView
            android:layout_width="50dp"
            android:layout_height="100dp"
            android:background="@color/colorAccent"
            />
    </LinearLayout>
    

    因为在 MyView 代码中 没有 绘制背景,所以这里手动在xml我呢间中设置 background

    相关文章

      网友评论

          本文标题:View绘制流程(四) - onDraw

          本文链接:https://www.haomeiwen.com/subject/bxtqlqtx.html