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);
    }

具体效果如下图所示:


4、绘制点

我们使用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);
    }

它的效果如图所示:


5、绘制椭圆

我们可以使用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);
    }

效果如下图所示:


6、绘制直线

绘制直线就比较简单了,使用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);
    }

效果如下图所示:


7、绘制圆角矩形

使用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);
    }

效果图如下所示:


8、绘制弧形或者扇形

这里使用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);
    }

效果图如下所示:


9、绘制自定义图形

说到画自定义图形,我们就会用到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,实际上这个小项目就是对这个课后作业的解答,我建议大家如果想学习的都去看看大神的这个系列的文章,写的真的很详细,值得一看!

发布了48 篇原创文章 · 获赞 47 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/JArchie520/article/details/78199580