转载请注明出处:http://blog.csdn.net/jarchie520/article/details/78199580
Android中的自定义View一直以来都是通往进阶的必备技能,之前这方面也看过一些,但是看的比较杂乱,最近打算系统的对它进行学习并且整理记录,今天先来看看最基础的部分————绘制基础。
一、绘制的简要说明
自定义绘制最主要的点就是重写绘制方法,当我们定义一个类去继承自View这个类时,会让你必须重写几个构造方法和onDraw(Canvas canvas)方法,那我们最常用的绘制方法就是这个onDraw方法,参数需要一个Canvas对象,我们绘制的关键就是通过Canvas提供的各个api去进行绘制、裁剪以及几何变换,这些我会慢慢的进行整理。本篇既然是基础,那么这里就只讲关于绘制的方法,即是drawXXX()方法。先把必须的东西都一下说完,在详细介绍,所以在这里还需要用到一个画笔类:Paint,这个类提供的一些api可以让我们设置画笔的颜色、形状、阴影等等,通过Canvas和Paint的搭配使用之后,我们就可以绘制出各种丰富多彩的图形了。
二、常用api的说明
1、颜色填充
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //给View上色为粉红色 canvas.drawColor(getResources().getColor(R.color.pageColor)); }
这里直接调用drawColor()方法,参数填充颜色即可,效果如下:
2、绘制圆形及环形
先看个简单的,绘制一个实心圆,这里我们需要借助Paint对象了哦,首先实例化一个Paint对象,然后调用canvas.drawCircle(圆心横坐标,圆心纵坐标,半径,画笔对象)方法,各个参数的含义已经很明确了,其中Paint.Style.FILL是实心模式,Paint.Style.STROKE是线条即空心模式。对了,需要说明的一点是,这里的坐标系和我们平时在数学中学的两维坐标系不同,android中每个View自己有一个坐标系,原点是View左上角的那个点,水平方向为X轴,向右为正向左为负,竖直方向为Y轴,向下为正向上为负,盗了大神一张图,上图:
除了画实心圆,我们还可以画空心圆,画带有颜色的实心圆,画圆环等等,因为使用也比较简单我就不详细说明了,具体来看一下代码,已经给出了注释:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); //开启抗锯齿 //实心圆 canvas.drawCircle(100, 300, 50, paint); //空心圆 paint.setStyle(Paint.Style.STROKE); //设置空心圆 canvas.drawCircle(250, 300, 50, paint); //粉红色实心圆 paint.setStyle(Paint.Style.FILL); paint.setColor(Color.parseColor("#FF4081")); canvas.drawCircle(400, 300, 50, paint); //线宽为10的空心圆 paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(10); //设置线的宽度 canvas.drawCircle(550, 300, 50, paint); }
这里需要说明的有一点Paint.ANTI_ALIAS_FLAG这个属性是给画笔添加抗锯齿效果,以保证图形边缘平滑,具体的实现效果为:
3、绘制矩形
我们可以使用canvas.drawRect(float left,float top,float right,float bottom,Paint paint)方法来绘制矩形,还有两个重载的方法,可以直接传Rect和RectF对象,具体代码如下:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); //画矩形 paint.setColor(Color.parseColor("#3F51B5")); canvas.drawRect(100,100,600,300,paint); // Rect rect = new Rect(100,100,600,300); // canvas.drawRect(rect,paint); // RectF rectF = new RectF(100,100,600,300); // canvas.drawRect(rectF,paint); }
具体效果如下图所示:
我们使用drawPoint(float x, float y, Paint paint)方法来画点,参数为点的坐标和画笔对象,点的形状可以通过paint.setStrokeCap(cap)方法来进行设置,ROUND为原点,SQUARE为方点,它们等同于绘制实现圆和实心矩形。另外drawPoints(float[] pts, Paint paint) 这个方法是画一组点,具体使用方法如下:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //手动关闭硬件加速,因为Canvas和Paint有一些方法不支持硬件加速 //在这里不加这句话Paint.Cap.Round不起效果,会是方形的 this.setLayerType(LAYER_TYPE_SOFTWARE,null); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); //画圆点 paint.setStrokeWidth(20); //设置点的大小 paint.setStrokeCap(Paint.Cap.ROUND); //设置点的形状为原型 paint.setColor(Color.parseColor("#FF4081")); canvas.drawPoint(100, 100, paint); //画方点 paint.setStrokeWidth(30); paint.setStrokeCap(Paint.Cap.SQUARE); //设置点的形状为方形 canvas.drawPoint(200, 100, paint); //画一组点 float[] points = {50,200,100,200,50,280,100,280}; canvas.drawPoints(points,paint); }
它的效果如图所示:
我们可以使用drawOval(float left, float top, float right, float bottom, Paint paint)方法来画椭圆,它还有一个重载的方法drawOval(RectF rect, Paint paint),参数很好理解了,边界坐标和画笔对象,具体在代码中来看它是如何使用的:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); //画实心椭圆 paint.setStyle(Paint.Style.FILL); //这个api必须在版本大于21是才能使用,否则程序会crash // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // canvas.drawOval(100,100,400,300,paint); // } RectF rectF = new RectF(100,100,400,300); canvas.drawOval(rectF,paint); //画空心椭圆 paint.setStyle(Paint.Style.STROKE); // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // canvas.drawOval(100,400,400,600,paint); // } RectF r = new RectF(100,400,400,600); canvas.drawOval(r,paint); }
效果如下图所示:
绘制直线就比较简单了,使用drawLine(float startX, float startY, float stopX, float stopY, Paint paint)方法画线,参数就是起始点的坐标和画笔对象。另外我们还可以绘制一组直线,组合出汉字或者其他图形,使用drawLines(float[] pts, Paint paint) 方法批量操作,下面同样通过代码来看它的使用:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setStrokeWidth(20); //画直线 canvas.drawLine(100,100,600,200,paint); //批量画线 float[] points = {200,300,600,300,400,300,400,700,200,700,600,700}; canvas.drawLines(points,paint); }
效果如下图所示:
使用drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)方法来画圆角矩形,参数分别为外轮廓的坐标,圆角的横向半径,纵向半径,画笔对象,使用起来也是很简单,直接上代码:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); //画实心圆角矩形 RectF r1 = new RectF(100,50,400,200); canvas.drawRoundRect(r1,30,30,paint); //画空心圆角矩形 paint.setStyle(Paint.Style.STROKE); RectF r2 = new RectF(100,250,400,400); canvas.drawRoundRect(r2,30,30,paint); }
效果图如下所示:
这里使用drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)方法来绘制弧形或扇形,通过查看源码我们可以发现,它底层是通过一个椭圆来描述弧形的,其中参数left、top、right、bottom是所在的椭圆的边界坐标,startAngle是弧形的起始角度,X轴的正向为0度的位置,顺时针为正逆时针为负,sweepAngle是弧形范围角度,useCenter表示是否连接到圆心,为true表示连接,就是扇形,为false表示不连接,就是弧形。具体使用方式见代码:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setStyle(Paint.Style.FILL); // 填充模式 RectF rectF = new RectF(200, 100, 600, 500); // 绘制扇形 canvas.drawArc(rectF, -110, 100, true, paint); // 绘制弧形 canvas.drawArc(rectF, 20, 140, false, paint); paint.setStyle(Paint.Style.STROKE); // 绘制不封口的弧形,即弧线 canvas.drawArc(rectF, 180, 60, false, paint); }
效果图如下所示:
说到画自定义图形,我们就会用到drawPath(Path path,Paint paint)这个方法了,它是通过描述路径的方式来绘制图形的,参数就是描述图形路径的对象和画笔对象。描述路径的方法又可分为两类:添加子图形和画线,即addXxx()和xxxTo()两类,我这里结合一个绘制心形的案例来介绍其中的一些方法,首先来看lineTo(float x, float y) / rLineTo(float x, float y) 方法,从当前位置向目标位置一条画线,x,y是目标点的坐标,当前位置就是最后一次调用Path方法的位置,初始值为(0,0),不同的是前者的参数是绝对坐标,后者的参数是相对坐标;moveTo(float x, float y) / rMoveTo(float x, float y) 这个方法是移动到目标位置,可以用来指定起始点的坐标;arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)这个方法用来画弧形,前面的参数和之前的意思一样,这里介绍一下forceMoveTo这个参数的意思,它是表示绘制时是否留下移动的轨迹;addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle)这个方法也是用来画弧形的,它和arcTo()的区别就是它直接将forceMoveTo置为true了;drawText(String text, float x, float y, Paint paint)这个方法是用来绘制文字的,参数是文本,位置坐标和画笔对象。具体的实现代码如下:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.parseColor("#FF4081")); Path path = new Path(); //初始化Path对象 RectF rectF = new RectF(100,200,300,400); path.addArc(rectF,-225,225); RectF r = new RectF(300,200,500,400); path.arcTo(r,-180,225,false); path.lineTo(300,542); canvas.drawPath(path,paint); }
效果图如下所示:
关于绘制基础部分的知识点就介绍这么多,最后通过两个小案例直方图和饼图进行知识点的巩固,我已经将完整的代码上传到GitHub上面了,欢迎大家批评指正。
直方图和饼图的效果图如下:
项目地址:https://github.com/JArchie/CustomViewDemo
我的这篇文章是基于在扔物线大神的系列课程的学习总结,这里也推荐给大家:https://juejin.im/user/552f20a7e4b060d72a89d87f,实际上这个小项目就是对这个课后作业的解答,我建议大家如果想学习的都去看看大神的这个系列的文章,写的真的很详细,值得一看!