美文网首页
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