前言:Canvas,是Android绘图机制的核心api,可以绘制出矩形、圆形、贝塞尔曲线、路径、文字等等各种图形,在Android的自定义View中需要大量用到这个类。现实生活中,我们在纸上画出一幅画,需要三样东西:画笔、画板、纸张。而Canvas就相当于画板,至于为什么不是纸张,咱们后面再说~

Paint

Paint,画笔,绘图三要素之一。常用api如下:

        //初始化画笔        paint = new Paint();        //设置抗锯齿        paint.setAntiAlias(true);        //设置画笔宽度        paint.setStrokeWidth(5);        //设置画笔颜色        paint.setColor(Color.RED);         //设置画笔透明度        paint.setAlpha(128);        //设置画笔样式        paint.setStyle(Paint.Style.STROKE);

经过这样设置的Paint对象,已经可以用来绘制各种各样的图形了,当然还有许多其它的api,不是很常用,这里就不做介绍。

Canvans来源

画板,我们在自定义View的时候,通常会重写其中的onDraw()方法:

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

这个方法默认提供了一个Canvas对象,通常我们会在自定义View的构造方法中去初始化Paint对象,然后配合提供的Canvas对象,就可以在自定义View的时候绘去制各种各样的图形。然而,这是重写View的方法时候默认提供的,如果我们想自己去初始化Canvans对象该怎么弄呢?也很简单:

  Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);  Canvas canvas = new Canvas(bitmap);

为啥要传入一个Bitmap对象呢?刚我们说现实生活中画一幅画的三要素是画板、画笔、纸张,画笔和画板都有了,而Bitmap就是最后一个要素:纸张。用以存储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            mNativeCanvasWrapper = nInitRaster(null);            mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(                    this, mNativeCanvasWrapper);        } else {            mFinalizer = null;        }    }

重点不看代码,看它的注释,Construct an empty raster canvas. Use setBitmap() to specify a bitmap to draw into。翻译过来就是:构造一个空的Canvas,使用setBitmap()方法指定一个Bitmap对象用于画入内容。意思就是,即便你使用空参数的构造方法,也需要调用setBitmap方法为其指定一个Bitmap对象,用于存储画出来的内容。以后你用Canvas的api画出来的各种图形,都是作用在你指定的Bitmap对象上的。 可以指定任意的Bitmap。好吧,这里也顺带说一下 Bitmap.Config这个类,createBitmap时传入的第三个参数,它是一个枚举类,用于决定图片存储的质量和大小。

每个像素信息只存储了alpha这一项信息。public enum Config {        //每个像素只存储透明度信息        ALPHA_8        //存储R、G、B信息三原色的信息。Red 5位;Green 6位;Blue 5位,5+6+5=16位=2个字节。        RGB_565        //存储透明度和三原色的信息。Alpha 4位;Red 4位;Green 4位;Blue 4位,4+4+4+4=16位=2个字节        ARGB_4444        //存储透明度和三原色的信息。Alpha 8位;Red 8位;Green 8位;Blue 8位,8+8+8+8=32位=4个字节        ARGB_8888                //图片以8个字节存储        RGBA_F16    }   

其实就是指定了每个像素的A、R、G、B所占的位数,合起来就是一个像素点所占的大小,可以认为每个像素点所占的大小越大,图片的质量越高,官方推荐使用ARGB_8888。举个例子,一张图片的分辨率是19201080,采用的是ARGB_8888格式,则它在内存中占用的大小是19201080*4/1000/1000=8.29M,这个值已经很大了,Android为每个应用分配的内存默认是16M,不同的厂商可能会修改这个值,但是也架不住这样的内存使用率。这就又涉及到图片的内存优化了,本篇博客重点不在这里,感兴趣的小伙伴可以自行百度Android图片内存优化相关的文章。好了,我们要开始画画了~

1、使用Canvas画圆

  @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //设置画笔        Paint paint = new Paint();        paint.setStyle(Paint.Style.FILL);        paint.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));        paint.setAntiAlias(true);        //画圆         canvas.drawCircle(getWidth()/2, getHeight()/2, 100, paint);    }

第一个参数是圆心坐标点的x值,第二个参数是圆心左边的y值,第三个参数是画笔,坐标相对于View的左上角。

 //画矩形 canvas.drawRect(100,100,300,300,paint);

前两个参数是矩形左上角的坐标,后两个参数是矩形右下角的坐标,最后一个是画笔对象。除了这种方法,还能直接传入一个Rect或者RectF对象:

 //画矩形 //RectF rect = new RectF(100,100,300,300); Rect rect = new Rect(100,100,300,300); canvas.drawRect(rect,paint);

效果是一样的,Rect和RectF都表示一个矩形的区域,功能都一样,不同的是Rect中的参数是整型的,RectF中的参数是单精度浮点型的。效果如下:


3、使用Canvas画圆角矩形

    //画圆角矩形    RectF rect = new RectF(100,100,300,300);    canvas.drawRoundRect(rect,10,10,paint);

Rect和Paint对象自不用说,中间的两个参数是啥呢?分别是矩形外接椭圆的x轴和y轴的半径,这么说不好理解:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <solid android:color="@color/colorAccent"/>    <corners android:radius="5dp"></corners></shape>

类似于上面代码中的radius属性。效果嘛,如下:


当然还有个重载的方法,把RectF对象拆成两个坐标点:

canvas.drawRoundRect(100,100,300,300,10,10,paint);

效果是一样的。

4、使用Canvas绘制椭圆

//绘制椭圆RectF rect = new RectF(100,100,400,300);canvas.drawOval(rect,paint);

为何要传入一个矩形的对象,这涉及到高中的数学知识了,已知一个矩形,其内切椭圆的值是唯一的,所以可以根据矩形来绘制出唯一的内切椭圆。



好吧,画出来的椭圆如下:

注意:如果矩形是正方形的话,则绘制出来椭圆的是圆形。

5、使用Canvas绘制弧线

弧线来自于圆或者椭圆,而椭圆来自于矩形内切,所以绘制弧线依旧需要一个矩形作为参数:

public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint) 

每个参数的意义如下:

  1. oval:矩形对象,弧线来自这个矩形的内切椭圆。
  2. float:起始角度。
  3. sweepAngle:弧线扫过的角度。注意不是结束角度,是弧线扫过的角度,方向是顺时针。
  4. useCenter:是否显示弧边。
  5. paint:画笔。

注:角度的定义参考高中数学象限知识。
好吧,画一个试试呗:

 //绘制弧线 RectF rect = new RectF(100,100,400,300); canvas.drawArc(rect,0,45,true,paint);

效果如下:


从0度开始,顺时针扫过45度,绘制出来的弧形(或者说扇形),如果把paint的style设置成Style.STROKE,图形还是一样的,只不过不填充了


如果不绘制弧边:

//绘制弧线,不显示弧边RectF rect = new RectF(100, 100, 400, 300);canvas.drawArc(rect, 0, 45, false, paint);

效果是这样的:


好吧,这个api既可以绘制扇形,也可以绘制一小段弧线,通过useCenter参数来控制即可。

6、使用Canvas绘制直线

public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
  1. startX:起点的x坐标。
  2. startY:起点的y坐标。
  3. stopX:终点的x坐标。
  4. stopY:终点的y坐标
  5. paint:画笔。

举例:

canvas.drawLine(30,30,100,100,paint);

效果:


绘制多条直线:

public void drawLines(float[] pts, Paint paint)
  1. pts:float数组,所有直线点的集合。比如:{100, 100, 200,200,300,300,500,500}则表示两条直线,(100,100)是第一条直线的起点,(200,200)是第一条直线的终点。(300,300)是第二条直线的起点,(500,500)是第二条直线的终点,以此内推。。。
  2. paint:画笔对象。

注:float数组中两个元素确定一个点,四个元素确定一条直线,元素个数可以是任意个数,少于四个元素则无法绘制任何直线,大于四个元素,则可以绘制 (int)(元素个数/4) 条直线。

举例:

 float[] pts = {100, 100, 200,200,300,300,500,500}; canvas.drawLines(pts,paint);

效果


还有个重载的方法:

 public void drawLines(float[] pts, int offset, int count,Paint paint)
  1. pts:float数组。
  2. offset:跳过的数组元素个数,这些数据将不参与绘制过程。
  3. count:实际参与绘制的数组元素个数。
  4. paint:画笔对象

举个例子:

float[] pts = {               100, 100, 200, 200,               300, 300, 400, 400,               500, 500, 600, 600        };canvas.drawLines(pts,4,4,paint);

这里有三条直线,跳过最前面四个元素,且实际参与绘制的数组元素个数为4,则数组中只有{300, 300, 400, 400}四个元素参与到绘制了,所以只会绘制中间一条直线。


7、使用Canvas填充控件颜色

假设一个自定义View的大小是100px*100px,如何去设置整个控件的颜色呢?当然,可以设置一个背景,也可以通过View自身的onDraw方法去绘制控件自身的颜色。

canvas.drawARGB(255,189,60,100);

四个值分别是A、R、G、B。


也可以使用drawColor()方法指定颜色:

  canvas.drawColor(Color.parseColor("#FFBD3C64"));

效果是一模一样的。

Canvas还有许多其它的api,如drawBitmap、drawPicture、drawText等等,这几个api涉及的东西比较多,这篇博客一时写不完,有时间会另写一篇博客介绍,文中如果有错误或者理解不到位的地方,欢迎小伙伴批评指正,完~

下一篇:Android绘图篇——绘制文本

更多相关文章

  1. Android(安卓)file类使用详解
  2. Android(安卓)camera2使用
  3. Android(安卓)核心分析 之六 -----IPC框架分析 Binder,Service,Se.
  4. android设置对话框背景透明度和弹出位置
  5. [置顶] android中自定义View
  6. Android中ActivityManagerService与应用程序(客户端)通信模型分
  7. Android创建和使用数据库SQLIte
  8. Android---45---使用AIDL Service传递复杂数据
  9. Android(安卓)OOM 解决方案

随机推荐

  1. fullcalendar.js - 在按钮点击时删除事
  2. 将JSON结果返回给ajax请求的MVC ErrorHan
  3. jQuery append xmlNode 修改 xml 内容
  4. Mulit jQuery UI Datepickers具有不同的
  5. Mvc 5和实体框架6中的Jquery多文件上载问
  6. jQuery的宽度、内宽和外宽、高度、内高和
  7. Jquery 1.9, JS -函数在Chrome中没有定义
  8. jQuery+EasyUI实现treegrid/datagride所
  9. 克隆文本并插入壁橱标题范围
  10. 用jQuery编写网页-表单检查