Android13 Drawable draw流程分析

Drawable的draw方法的作用是将Canvas(画布)的内容绘制到Drawable中,然后通过View的setBackground(Drawable background)方法设置View的背景,Drawable的draw方法代码如下:

//frameworks/base/graphics/java/android/graphic/drawable/Drawable.java
public abstract class Drawable {
    public abstract void draw(@NonNull Canvas canvas);
}

GradientDrawable draw

Drawable是一个抽象类,draw方法是一个抽象方法,绘制View背景常用的是Drawable包括ColorDrawable、GradientDrawable、BitmapDrawable等,其中GradientDrawable是一种常用的Drawable类型,用于绘制各种形状的背景,下面我们继续分析GradientDrawable的draw方法:

//frameworks/base/graphics/java/android/graphic/drawable/GradientDrawable.java
public class GradientDrawable extends Drawable {
    private Paint mLayerPaint;
    private Paint mStrokePaint;   // optional, set by the caller
    private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    public void draw(Canvas canvas) {
        if (!ensureValidRect()) {
            // nothing to draw
            return;
        }


        // remember the alpha values, in case we temporarily overwrite them
        // when we modulate them with mAlpha
        final int prevFillAlpha = mFillPaint.getAlpha();
        final int prevStrokeAlpha = mStrokePaint != null ? mStrokePaint.getAlpha() : 0;
        // compute the modulate alpha values
        final int currFillAlpha = modulateAlpha(prevFillAlpha);
        final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha);


        final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint != null &&
                mStrokePaint.getStrokeWidth() > 0;
        final boolean haveFill = currFillAlpha > 0;
        final GradientState st = mGradientState;
        final ColorFilter colorFilter = mColorFilter != null ? mColorFilter : mBlendModeColorFilter;


        /*  we need a layer iff we're drawing both a fill and stroke, and the
            stroke is non-opaque, and our shapetype actually supports
            fill+stroke. Otherwise we can just draw the stroke (if any) on top
            of the fill (if any) without worrying about blending artifacts.
         */
        final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
                 currStrokeAlpha < 255 && (mAlpha < 255 || colorFilter != null);


        /*  Drawing with a layer is slower than direct drawing, but it
            allows us to apply paint effects like alpha and colorfilter to
            the result of multiple separate draws. In our case, if the user
            asks for a non-opaque alpha value (via setAlpha), and we're
            stroking, then we need to apply the alpha AFTER we've drawn
            both the fill and the stroke.
        */
        if (useLayer) {
            if (mLayerPaint == null) {
                mLayerPaint = new Paint();
            }
            mLayerPaint.setDither(st.mDither);
            mLayerPaint.setAlpha(mAlpha);
            mLayerPaint.setColorFilter(colorFilter);


            float rad = mStrokePaint.getStrokeWidth();
            canvas.saveLayer(mRect.left - rad, mRect.top - rad,
                             mRect.right + rad, mRect.bottom + rad,
                             mLayerPaint);


            // don't perform the filter in our individual paints
            // since the layer will do it for us
            mFillPaint.setColorFilter(null);
            mStrokePaint.setColorFilter(null);
        } else {
            /*  if we're not using a layer, apply the dither/filter to our
                individual paints
            */
            mFillPaint.setAlpha(currFillAlpha);
            mFillPaint.setDither(st.mDither);
            mFillPaint.setColorFilter(colorFilter);
            if (colorFilter != null && st.mSolidColors == null) {
                mFillPaint.setColor(mAlpha << 24);
            }
            if (haveStroke) {
                mStrokePaint.setAlpha(currStrokeAlpha);
                mStrokePaint.setDither(st.mDither);
                mStrokePaint.setColorFilter(colorFilter);
            }
        }


        switch (st.mShape) {
            case RECTANGLE:
                if (st.mRadiusArray != null) {
                    buildPathIfDirty();
                    canvas.drawPath(mPath, mFillPaint);
                    if (haveStroke) {
                        canvas.drawPath(mPath, mStrokePaint);
                    }
                } else if (st.mRadius > 0.0f) {
                    // since the caller is only giving us 1 value, we will force
                    // it to be square if the rect is too small in one dimension
                    // to show it. If we did nothing, Skia would clamp the rad
                    // independently along each axis, giving us a thin ellipse
                    // if the rect were very wide but not very tall
                    float rad = Math.min(st.mRadius,
                            Math.min(mRect.width(), mRect.height()) * 0.5f);
                    canvas.drawRoundRect(mRect, rad, rad, mFillPaint);
                    if (haveStroke) {
                        canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
                    }
                } else {
                    if (mFillPaint.getColor() != 0 || colorFilter != null ||
                            mFillPaint.getShader() != null) {
                        canvas.drawRect(mRect, mFillPaint);
                    }
                    if (haveStroke) {
                        canvas.drawRect(mRect, mStrokePaint);
                    }
                }
                break;
            case OVAL:
                canvas.drawOval(mRect, mFillPaint);
                if (haveStroke) {
                    canvas.drawOval(mRect, mStrokePaint);
                }
                break;
            case LINE: {
                RectF r = mRect;
                float y = r.centerY();
                if (haveStroke) {
                    canvas.drawLine(r.left, y, r.right, y, mStrokePaint);
                }
                break;
            }
            case RING:
                Path path = buildRing(st);
                canvas.drawPath(path, mFillPaint);
                if (haveStroke) {
                    canvas.drawPath(path, mStrokePaint);
                }
                break;
        }


        if (useLayer) {
            canvas.restore();
        } else {
            mFillPaint.setAlpha(prevFillAlpha);
            if (haveStroke) {
                mStrokePaint.setAlpha(prevStrokeAlpha);
            }
        }
    }
}

上面方法主要处理如下:

1、调用canvas(Canvas)的saveLayer方法保存Layer。

2、根据不同的参数调用canvas(Canvas)的drawPath方法绘制路径。

3、根据不同的参数调用canvas(Canvas)的drawRoundRect方法绘制绘制圆角矩形。

4、根据不同的参数调用canvas(Canvas)的drawRect方法绘制矩形。

5、根据不同的参数调用canvas(Canvas)的drawOval方法绘制椭圆。

6、根据不同的参数调用canvas(Canvas)的drawLine方法绘制线。

下面分别进行分析:

Canvas saveLayer

调用canvas(Canvas)的saveLayer方法保存Layer:

Android13 Canvas saveLayer流程分析-CSDN博客

Canvas drawPath

根据不同的参数调用canvas(Canvas)的drawPath方法绘制路径:

Android13 Canvas drawPath流程分析-CSDN博客

Canvas drawRoundRect

根据不同的参数调用canvas(Canvas)的drawRoundRect方法绘制绘制圆角矩形:

Android13 Canvas drawRoundRect流程分析-CSDN博客

Canvas drawRect

根据不同的参数调用canvas(Canvas)的drawRect方法绘制矩形:

Android13 Canvas drawRect流程分析-CSDN博客

Canvas drawOval

根据不同的参数调用canvas(Canvas)的drawOval方法绘制椭圆:

Android Canvas drawOval流程分析-CSDN博客

Canvas drawLine

根据不同的参数调用canvas(Canvas)的drawLine方法绘制线:

Android13 Canvas drawLine流程分析-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值