美文网首页
自定义View之HenCoder学习笔记

自定义View之HenCoder学习笔记

作者: kim_liu | 来源:发表于2018-06-21 16:35 被阅读61次

    本文是学习公众号 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 中的变换。

    相关文章

      网友评论

          本文标题:自定义View之HenCoder学习笔记

          本文链接:https://www.haomeiwen.com/subject/mrexyftx.html