自定义View之HenCoder学习笔记

2018-06-21  本文已影响61人  kim_liu

本文是学习公众号 hencoder 中的自定义View部分的学习笔记。

1-1 onDraw()和Paint详解

具体参考http://hencoder.com/ui-1-1/ 写的非常详细

练习:画弧形,扇形,心形,直方图,饼图

1-1-1.弧形 扇形 使用 canvas.drawArc()

drawArc() 是使用一个椭圆来描述弧形的。left, top, right, bottom 描述的是这个弧形所在的椭圆;startAngle 是弧形的起始角度(x 轴的正向,即正右的方向,是 0 度的位置;顺时针为正角度,逆时针为负角度),sweepAngle 是弧形划过的角度;useCenter 表示是否连接到圆心,如果不连接到圆心,就是弧形,如果连接到圆心,就是扇形。

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILL); // 填充模式
//        canvas.drawOval(200, 100, 800, 500,paint);
        canvas.drawArc(200, 100, 800, 500, -110, 100, true, paint); // 绘制扇形
        canvas.drawArc(200, 100, 800, 500, 20, 140, false, paint); // 绘制弧形
        paint.setStyle(Paint.Style.STROKE); // 画线模式
        canvas.drawArc(200, 100, 800, 500, 180, 60, false, paint); // 绘制不封口的弧形

1-1-2 心形

使用drawPath(Path path, Paint paint)
Path类中的各种方法Hencoder已经写的非常清楚

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);
        paint.setStyle(Paint.Style.STROKE);
        Path path = new Path();
        //画圆弧,圆弧的最左侧距离y轴距离200 最上距离x轴距离200,
        //最下距离x轴400 最右距离y轴400
        // 开始弧度-225 弧形扫过的角度225
        path.addArc(200, 200, 400, 400, -225, 225);
        //画圆弧,圆弧的最左侧距离y轴距离400 最上距离x轴距离200,
        //最下距离x轴400 最右距离y轴600 
        //开始弧度-180 弧形扫过的角度225 保留移动痕迹
        path.arcTo(400, 200, 600, 400, -180, 225, false);
        path.lineTo(400, 542);//从当前位置画线到(400,542)
        path.close();//闭合图形
        canvas.drawPath(path,paint);
图片.png

该图是对这句代码的解释,剩下的几句代码的解释注释中都已写的很清楚。

        //画圆弧,圆弧的最左侧距离y轴距离200 最上距离x轴距离200,
        // 最下距离x轴400 最右距离y轴400 开始弧度-225 弧形扫过的角度225
        path.addArc(200, 200, 400, 400, -225, 225);

1-1-3 画直方图

确定好坐标后,画坐标系,文字,矩形,如下图所示


图片.png
        Paint paint = new Paint();
        //绘制坐标系
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(2);
        paint.setColor(Color.WHITE);
        Path path = new Path();
        path.moveTo(150,100);//移动起点到(150,100)
        path.lineTo(150,500);//从(150,100)开始画线,画到(150,150)处
        path.lineTo(900,500);
        canvas.drawPath(path,paint);

        //绘制文字
        paint.setTextSize(22);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(1);
        canvas.drawText("Froyo",200,520,paint);
        canvas.drawText("GB",315,520,paint);
        canvas.drawText("ICS",415,520,paint);
        canvas.drawText("JB",515,520,paint);
        canvas.drawText("KitKat",605,520,paint);
        canvas.drawText("L",725,520,paint);
        canvas.drawText("M",825,520,paint);

        //绘制长方形
        paint.setColor(getResources().getColor(R.color.green_light));
        paint.setStyle(Paint.Style.FILL);
        canvas.drawRect(190,495,270,500,paint);
        canvas.drawRect(290,485,370,500,paint);
        canvas.drawRect(390,485,470,500,paint);
        canvas.drawRect(490,350,570,500,paint);
        canvas.drawRect(590,250,670,500,paint);
        canvas.drawRect(690,180,770,500,paint);
        canvas.drawRect(790,370,870,500,paint);

1-1-4 绘制饼图

1.绘制扇形
分析如下图所示


饼图分析.png

此处使用的是canvas的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 表示是否连接到圆心,如果不连接到圆心,就是弧形,如果连接到圆心,就是扇形。

注意要计算好角度
 Paint paint = new Paint();
        Path path = new Path();
        //红色区域
        paint.setColor(getResources().getColor(R.color.red_light));
        canvas.drawArc(200,150,558,500,-180,125,true,paint);
        //圆心(385,325) 直径350

        //黄色区域
        paint.setColor(getResources().getColor(R.color.yellow_light));
        //left, top, right, bottom 描述的是这个弧形所在的椭圆;startAngle 是弧形的起始角度
        //sweepAngle 是弧形划过的角度;useCenter 表示是否连接到圆心
        canvas.drawArc(210,157,568,507,-55,55,true,paint);

        //紫色区域
        paint.setColor(getResources().getColor(R.color.purple_light));
        canvas.drawArc(210,157,568,507,3,8,true,paint);

        //灰色区域
        paint.setColor(getResources().getColor(R.color.grey_light));
        canvas.drawArc(210,157,568,507,13,7,true,paint);
        //青色区域
        paint.setColor(getResources().getColor(R.color.cyan_light));
        canvas.drawArc(210,157,568,507,22,55,true,paint);

        //蓝色区域
        paint.setColor(getResources().getColor(R.color.blue_light));
        canvas.drawArc(210,157,568,507,79,98,true,paint);

2.绘制白色的指示线
白色指示线的终点在每个弧形中点的位置,计算出每个白线中点。

        //画线
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(1);
       path.moveTo(170,180);
       path.lineTo(240,180);
       path.lineTo(250,200);
       canvas.drawPath(path,paint);

       //第二条线 (385,325)圆心
        path.moveTo(680,250);
        path.lineTo(580,250);
        path.lineTo(550,270);
        canvas.drawPath(path,paint);

        //第三条线
        path.moveTo(680,370);
        path.lineTo(640,370);
        path.lineTo(620,350);
        path.lineTo(565,350);
        canvas.drawPath(path,paint);

        //第四条线
        path.moveTo(680,400);
        path.lineTo(640,400);
        path.lineTo(620,380);
        path.lineTo(563,380);
        canvas.drawPath(path,paint);

        //第五条线
        path.moveTo(600,470);
        path.lineTo(550,470);
        path.lineTo(520,450);
        canvas.drawPath(path,paint);

        //第六条线
        path.moveTo(170,470);
        path.lineTo(240,470);
        path.lineTo(250,450);
        canvas.drawPath(path,paint);

       //绘制文字
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(20);
        canvas.drawText("Lollipop",90,185,paint);
        canvas.drawText("Marshmallow",690,255,paint);
        canvas.drawText("Gingerbread",690,375,paint);
        canvas.drawText("Ice Cream Sandwich",690,405,paint);
        canvas.drawText("Jelly Bean",610,475,paint);
        canvas.drawText("KitKat",100,475,paint);

1-2 Paint 详解

具体参考:http://hencoder.com/ui-1-2/ 写的十分详细

1-3 drawText() 文字的绘制

具体参考:http://hencoder.com/ui-1-3/ 也是写的十分详细

1-4 Canvas 对绘制的辅助 clipXXX() 和 Matrix

具体参考: http://hencoder.com/ui-1-4/ 知识点写的十分详细

1-4-1 clipXXX()方法 裁切方法

1) clipRect() 在矩形范围内裁切

      //加上save和restore 恢复到裁切之前的状态 不然后面都会裁切掉
        canvas.save();
        canvas.clipRect(left,top, left+300,top+200);
        canvas.drawBitmap(bitmap, left, top, paint);
        canvas.restore();
  1. clipPath() 根据Path形状裁切
   //  第一种:   1.画出path 圆
        path1.addCircle(point1.x + 200,point1.y + 200,150, Path.Direction.CW);
       //2.根据path裁切
        canvas.save();
        canvas.clipPath(path1);
        canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
        canvas.restore();



        //第二种:
        /**
         * FillType 有四个值:
         *  1.EVEN_ODD: Specifies that "inside" is computed by an odd number of edge crossings.
         *  2.INVERSE_EVEN_ODD:Same as EVEN_ODD, but draws outside of the path, rather than inside.
         *  3.WINDING:Specifies that "inside" is computed by a non-zero sum of signed edge crossings.
         *  4.INVERSE_WINDING:Same as WINDING, but draws outside of the path, rather than inside.
         */
        path2.setFillType(Path.FillType.INVERSE_WINDING);
        path2.addCircle(point2.x+ 200,point2.y + 200,150, Path.Direction.CCW);

       canvas.save();
        canvas.clipPath(path2);
        canvas.drawBitmap(bitmap, point2.x, point2.y, paint);
        canvas.restore();

上面Path的FillType,详细解释可见:
http://android.jobbole.com/83427/

1-4-2 几何变换

几何变换的使用大概分为三类:
1. 使用 Canvas 来做常见的二维变换;
2.使用 Matrix 来做常见和不常见的二维变换;
3.使用 Camera 来做三维变换。

1) 使用 Canvas 来做常见的二维变换:
注意:1.canvas的几何变换可以叠加使用,但是叠加时,要倒着写,需要先实现的效果写在后面
2.在做几何变换之前,需要使用save保存状态,做之后使用restore恢复状态
1.1 Canvas.translate(float dx, float dy) 平移

        canvas.save();
        //向右移动200
        canvas.translate(200,0);
        canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
        canvas.restore();
        canvas.save();
        //向左移动100
        canvas.translate(-100,0);
        canvas.drawBitmap(bitmap, point2.x, point2.y, paint);
        canvas.restore();

1.2 旋转Canvas.rotate(float degrees, float px, float py)

        canvas.save();
        //如果想要两个效果叠加使用 需要倒着写,比如说想要先旋转再移动 需要把移动写在旋转之前
        canvas.rotate(45,point1.x + bitmapWidth/2,point1.y+ bitmapHeight/2);
        canvas.translate(200,100);
        //先移动 再绘制 先旋转 再绘制
        canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
        canvas.restore();

1.3 缩放 Canvas.scale(float sx, float sy, float px, float py)

        canvas.save();
        //参数里的 sx sy 是横向和纵向的放缩倍数; px py 是放缩的轴心。
        canvas.scale(1.3f,1.3f,point1.x + bitmapWidth/2 ,point1.y + bitmapHeight/2);
        canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
        canvas.restore();

1.4 skew(float sx, float sy) 错切

  //参数里的 sx 和 sy 是 x 方向和 y 方向的错切系数。
        canvas.save();
        canvas.skew(0, 0.5f);
        canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
        canvas.restore();
  1. 使用 Matrix 来做变换
    2.1 使用 Matrix 来做常见变换
    Matrix 做常见变换的方式:
    1.创建 Matrix 对象;
    2.调用 Matrix 的 pre/postTranslate/Rotate/Scale/Skew() 方法来设置几何变换,Matrix做几何变换时,可以自己设定顺序,pre是插入在某个效果之前,post是在某个效果之后。;
    3.使用 Canvas.setMatrix(matrix) 或 Canvas.concat(matrix) 来把几何变换应用到 Canvas。

1)平移

       canvas.save();
        matrix.reset();
        matrix.postTranslate(-100, -100);
        canvas.concat(matrix);
        canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
        canvas.restore();

        canvas.save();
        matrix.reset();
        matrix.postTranslate(200, 0);
        canvas.concat(matrix);
        canvas.drawBitmap(bitmap, point2.x, point2.y, paint);
        canvas.restore();
  1. 缩放

把 Matrix 应用到 Canvas 有两个方法: Canvas.setMatrix(matrix) 和 Canvas.concat(matrix)。
1.Canvas.setMatrix(matrix):用 Matrix 直接替换 Canvas 当前的变换矩阵,即抛弃 Canvas 当前的变换,改用 Matrix 的变换(注:根据下面评论里以及我在微信公众号中收到的反馈,不同的系统中 setMatrix(matrix) 的行为可能不一致,所以还是尽量用 concat(matrix) 吧);
2.Canvas.concat(matrix):用 Canvas 当前的变换矩阵和 Matrix 相乘,即基于 Canvas 当前的变换,叠加上 Matrix 中的变换。

上一篇下一篇

猜你喜欢

热点阅读