View绘制4-onDraw

已知通过onMeasure()测绘view大小,通过onLayout()知道view位置,然后就是在draw阶段实现具体绘制了

View-draw()的绘制过程

 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;

        /* * 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) {
            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
            dispatchDraw(canvas);

            // Step 6, draw decorations (scrollbars)
            onDrawScrollBars(canvas);

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

            // we're done...
            return;
        }

        /* * Here we do the full fledged routine... * (this is an uncommon case where speed matters less, * this is why we repeat some of the tests that have been * done above) */

        // Step 2, save the canvas' layers
        int paddingLeft = mPaddingLeft;

        final boolean offsetRequired = isPaddingOffsetRequired();
        if (offsetRequired) {
            paddingLeft += getLeftPaddingOffset();
        }

        int left = mScrollX + paddingLeft;
        int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
        int top = mScrollY + getFadeTop(offsetRequired);
        int bottom = top + getFadeHeight(offsetRequired);
        //省略...
        // 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 (scrollbars)
        onDrawScrollBars(canvas);

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

源码注释已经给出了绘制的指引:
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)
翻译过来就是:
1.绘制背景 backgrond.draw(canvas)
2.如果有必要画布保存canvas.save()
3.绘制自己onDraw()
4.绘制childrendispatchDraw()
5.如果有必要复原画布canvas.restore()
6.绘制装饰onDrawScollBars()
这里我们只关注onDraw()绘制自己

Paint/Canvas-画笔/画布

先看Canvas的构造函数

    /** * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to * draw into. The initial target density is {@link Bitmap#DENSITY_NONE}; * this will typically be replaced when a target bitmap is set for the * canvas. */
    public Canvas() {
        if (!isHardwareAccelerated()) {
            // 0 means no native bitmap
            mNativeCanvas = initRaster(0);
            mFinalizer = new CanvasFinalizer(mNativeCanvas);
        } else {
            mFinalizer = null;
        }
    }

    /** * Construct a canvas with the specified bitmap to draw into. The bitmap * must be mutable. * * <p>The initial target density of the canvas is the same as the given * bitmap's density. * * @param bitmap Specifies a mutable bitmap for the canvas to draw into. */
    public Canvas(Bitmap bitmap) {
        if (!bitmap.isMutable()) {
            throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
        }
        throwIfCannotDraw(bitmap);
        mNativeCanvas = initRaster(bitmap.ni());
        mFinalizer = new CanvasFinalizer(mNativeCanvas);
        mBitmap = bitmap;
        mDensity = bitmap.mDensity;
    }

按照注释的说法并不推荐使用无参构造函数Canvas()而是建议我们使用Canvas(Bitmap bitmap)同时Bitmap是可以修改的,否则将会抛出异常throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
系统也是这样做的:
onDraw( )的输入参数是一个canvas,它与我们自己创建的canvas不同。这个系统传递给我们的canvas来自于ViewRootImpl的Surface,在绘图时系统将会SkBitmap设置到SkCanvas中并返回与之对应Canvas。所以,在onDraw()中也是有一个Bitmap的,这个Bitmap是由系统创建。

Paint对象的方法:

void  setARGB(int a, int r, int g, int b)  设置Paint对象颜色,参数一为alpha透明通道
void  setAlpha(int a)  设置alpha不透明度,范围为0~255
void  setAntiAlias(boolean aa)  //是否抗锯齿,默认值是false
void  setColor(int color)  //设置颜色,这里Android内部定义的有Color类包含了一些常见颜色定义
void  setFakeBoldText(boolean fakeBoldText)  //设置伪粗体文本
void  setLinearText(boolean linearText)  //设置线性文本
PathEffect  setPathEffect(PathEffect effect)  //设置路径效果
Rasterizer  setRasterizer(Rasterizer rasterizer) //设置光栅化
Shader  setShader(Shader shader)  //设置阴影 ,我们在后面会详细说一下Shader对象的
void  setTextAlign(Paint.Align align)  //设置文本对齐
void  setTextScaleX(float scaleX)  //设置文本缩放倍数,1.0f为原始
void  setTextSize(float textSize)  //设置字体大小
Typeface  setTypeface(Typeface typeface)  //设置字体,Typeface包含了字体的类型,粗细,还有倾斜、颜色等

Canvas

canvas.translate  坐标系平移
canvas.rotate   坐标系旋转
canvas.clipRect 截取
canvas.save和canvas.restore  存储  复原

PorterDuffXfermode

常常在图片截取的时候会用到,例如:图片转换成圆角矩形图片,转换成圆形图片,聚光灯效果…等等
View绘制4-onDraw_第1张图片
1.PorterDuff.Mode.CLEAR

所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC

显示上层绘制图片
3.PorterDuff.Mode.DST

显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER

正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER

上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN

取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN

取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT

取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT

取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP

取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP

取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
不相交的部分

13.PorterDuff.Mode.DARKEN
显示两图层全部区域交集部分变暗

14.PorterDuff.Mode.LIGHTEN
显示两图层全部区域交集部分变亮

15.PorterDuff.Mode.MULTIPLY

显示两图层相交部分,交集变暗
16.PorterDuff.Mode.SCREEN
显示两图层全部区域且相交部分变成透明

其他

Shader-颜色渲染器

BitmapShader———图像渲染
LinearGradient——–线性渲染
RadialGradient——–环形渲染
SweepGradient——–扫描渲染
ComposeShader——组合渲染

Matrix 矩阵变幻

平移、缩放、颜色变化

你可能感兴趣的:(View绘制4-onDraw)