Android 详解Canvas与Paint的关系并附有代码实例 - 奇乐云's blog - 奇乐云的个人博客

会飞的鱼

奇乐云
首页 » Android » Android 详解Canvas与Paint的关系并附有代码实例

Android 详解Canvas与Paint的关系并附有代码实例

前言

Canvas在我们的绘制中扮演的角色其实是会话,我们通常情况下都知道我们能使用Canvas调相关方法去画圆型,矩形图片等,但是最终其实真正的绘制并不是在我们的android层面进行的。当然使用Canvas去画一些东西我们必须要知道四个基本组件如下:

1.一个位图来保存像素

2.Canvas持有绘画的方法drawxx:用画布绘制

3.绘画的模版:(eg.  Rect,Path,text,Bitmap)

4.paint:绘画的颜色和样式



Canvas与Paint关系:

源码分析
1.
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
        @NonNull Paint paint) {
    drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
            paint);
}


2.
public void drawArc(float left, float top, float right, float bottom, float startAngle,
        float sweepAngle, boolean useCenter, @NonNull Paint paint) {
    native_drawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
            useCenter, paint.getNativeInstance());
}

3.
private static native void native_drawArc(long nativeCanvas, float left, float top,
                                          float right, float bottom,
                                          float startAngle, float sweep, boolean useCenter,
                                          long nativePaint);



通过上述代码我问发现最后调用到的是底层的一个native_drawArc的本地方法,那么其实本身android的绘制是交由系统底层的so库完成,也就是C的代码。那么在此处我们可以得出一个结论就是,Canvas并不是具体的执行者,而是一个传达着, 在Canvas当中我们会将所有的参数信息设置好,然后交由底层去绘制。



Paint职责
/**
 * The Paint class holds the style and color information about how to draw
 * geometries, text and bitmaps.
 * Paint类保存关于如何绘制的样式和颜色信息
 几何图形,文本和位图。
 */
public class Paint {

    private long mNativePaint;
    private long mNativeShader = 0;



具体应用实例:

public class ShapesView extends View {
    private final Paint mNormalPaint;
    private final Paint mStrokePaint;
    private final Paint mFillPaint;
    private final RectF mRect;
    private final RectF mOval;
    private final RectF mArc;
    private final Path mTriangle;
    private TextPaint mSubTitlePaint;
    Paint paint;


    public ShapesView(Context c) {
        super(c);

        mRect = new RectF(0.0f, 0.0f, 160.0f, 90.0f);

        mNormalPaint = new Paint();
        mNormalPaint.setAntiAlias(true);
        mNormalPaint.setColor(0xff0000ff);
        mNormalPaint.setStrokeWidth(6.0f);
        mNormalPaint.setStyle(Paint.Style.FILL_AND_STROKE);

        mStrokePaint = new Paint();
        mStrokePaint.setAntiAlias(true);
        mStrokePaint.setColor(0xff0000ff);
        mStrokePaint.setStrokeWidth(6.0f);
        mStrokePaint.setStyle(Paint.Style.STROKE);

        mFillPaint = new Paint();
        mFillPaint.setAntiAlias(true);
        mFillPaint.setColor(0xff0000ff);
        mFillPaint.setStyle(Paint.Style.FILL);

        mOval = new RectF(0.0f, 0.0f, 80.0f, 45.0f);
        mArc = new RectF(0.0f, 0.0f, 100.0f, 120.0f);

        mTriangle = new Path();
        mTriangle.moveTo(0.0f, 90.0f);
        mTriangle.lineTo(45.0f, 0.0f);
        mTriangle.lineTo(90.0f, 90.0f);
        mTriangle.close();


        mSubTitlePaint = new TextPaint();
        // 设置paint颜色
        mSubTitlePaint.setColor(Color.RED);
        // 设置字体大小DP
        mSubTitlePaint.setTextSize(36);
        // 设置抗锯齿
        mSubTitlePaint.setAntiAlias(true);
        // 设置字体居中
        mSubTitlePaint.setTextAlign(Paint.Align.CENTER);
        mSubTitlePaint.setStrikeThruText(true);

        paint = new Paint();

        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.BLACK);
        paint.setAlpha(80);
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        paint.setShadowLayer(10, 10, 10, Color.BLACK);
        paint.setTextSize(30);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        canvas.translate(50.0f, 50.0f);
        canvas.drawRoundRect(mRect, 6.0f, 6.0f, mNormalPaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawRoundRect(mRect, 6.0f, 6.0f, mStrokePaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawRoundRect(mRect, 6.0f, 6.0f, mFillPaint);
        canvas.restore();

        canvas.save();
        canvas.translate(250.0f, 50.0f);
        canvas.drawCircle(80.0f, 45.0f, 45.0f, mNormalPaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawCircle(80.0f, 45.0f, 45.0f, mStrokePaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawCircle(80.0f, 45.0f, 45.0f, mFillPaint);
        canvas.restore();

        canvas.save();
        canvas.translate(450.0f, 50.0f);
        canvas.drawOval(mOval, mNormalPaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawOval(mOval, mStrokePaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawOval(mOval, mFillPaint);
        canvas.restore();

        canvas.save();
        canvas.translate(625.0f, 50.0f);
        canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mNormalPaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mStrokePaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mFillPaint);
        canvas.restore();

        canvas.save();
        canvas.translate(825.0f, 50.0f);
        canvas.drawArc(mArc, -30.0f, 70.0f, true, mNormalPaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawArc(mArc, -30.0f, 70.0f, true, mStrokePaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawArc(mArc, -30.0f, 70.0f, true, mFillPaint);
        canvas.restore();

        canvas.save();
        canvas.translate(950.0f, 50.0f);
        canvas.drawArc(mArc, 30.0f, 100.0f, false, mNormalPaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawArc(mArc, 30.0f, 100.0f, false, mStrokePaint);

        canvas.translate(0.0f, 110.0f);
        canvas.drawArc(mArc, 30.0f, 100.0f, false, mFillPaint);
        canvas.restore();

        canvas.save();
        canvas.translate(50.0f, 400.0f);
        canvas.drawPath(mTriangle, mNormalPaint);

        canvas.translate(110.0f, 0.0f);
        canvas.drawPath(mTriangle, mStrokePaint);

        canvas.translate(110.0f, 0.0f);
        canvas.drawPath(mTriangle, mFillPaint);
        canvas.restore();

        canvas.drawText("哈哈哈", 100, 600, mSubTitlePaint);



        canvas.drawText("画一个很大的圆", 50, 850, paint);

        //cx和cy为圆点的坐标
        int radius = 80;
        int offest = 40;
        int startX = radius + offest;
        int startY = radius + offest + 40;

        canvas.drawCircle(startX*3, startY*5, radius, paint);

        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint.setShadowLayer(20, -20, 700, Color.BLACK);
        canvas.drawCircle(startX + radius * 2 + offest, startY, radius, paint);
    }
}

运行效果图如下:


4f7a2e7977848e614d1df3fd75a39fd4_70.png

4697834d06886c37d1ea1b92839de3ae_20180507141255495.png

Paint常用方法
void setAntiAlias(boolean aa); 是否抗锯齿
void setDither(boolean dither) 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰 
void setLinearText(boolean linearText) 设置线性文本
void setSubpixelText(boolean subpixelText) 设置该项为true,将有助于文本在LCD屏幕上的显示效果 
void setUnderlineText(boolean underlineText) 设置下划线
void setStrikeThruText(boolean strikeThruText) 设置带有删除线的效果
void setFakeBoldText(boolean fakeBoldText) 设置伪粗体文本,设置在小字体上效果会非常差
void setFilterBitmap(boolean filter)

如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作

加快显示速度,本设置项依赖于dither和xfermode的设置

void setStyle(Style style) 设置画笔风格,空心或者实心 FILL,FILL_OR_STROKE,或STROKE
Paint.Style.STROKE 表示当前只绘制图形的轮廓,而Paint.Style.FILL表示填充图形。
void setColor(int color) 设置颜色值
void setAlpha(int a) 设置透明图0~255,要在setColor后面设置才生效
void setARGB(int a, int r, int g, int b) 设置RGB及透明度
void setStrokeWidth(float width);
void setStrokeMiter(float miter);
当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
void setStrokeCap(Cap cap) 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷末端的图形样式
//如圆形样式Cap.ROUND,或方形样式Cap.SQUARE 
void setStrokeJoin(Join join) 设置绘制时各图形的结合方式,如平滑效果等 
Shader setShader(Shader shader) 设置图像效果,使用Shader可以绘制出各种渐变效果 
ColorFilter setColorFilter(ColorFilter filter) 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
Xfermode setXfermode(Xfermode xfermode) 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
PathEffect setPathEffect(PathEffect effect) 设置绘制路径的效果,如点画线等
MaskFilter setMaskFilter(MaskFilter maskfilter) 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等 
Rasterizer setRasterizer(Rasterizer rasterizer) 设置光栅化
 void setShadowLayer(float radius, float dx, float dy, int color) 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色
//注意:在Android4.0以上默认开启硬件加速,有些图形的阴影无法显示。关闭View的硬件加速 view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
void setTextAlign(Align align) 设置文本对齐
void setTextSize(float textSize) 设置字体大小
void setTextScaleX(float scaleX) 设置文本缩放倍数,1.0f为原始
void setTextSkewX(float skewX) 设置斜体文字,skewX为倾斜弧度
Typeface setTypeface(Typeface typeface) 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等

文章如无特别注明均为原创! 作者: 奇乐云, 转载或复制请以 超链接形式 并注明出处 奇乐云's blog - 奇乐云的个人博客
原文地址《 Android 详解Canvas与Paint的关系并附有代码实例》发布于2019-3-2

分享到:
打赏

评论

游客

切换注册

登录

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册