Canvas 基本用法


Canvas坐标系

Canvas坐标系Canvas坐标系指的是Canvas本身的坐标系,Canvas坐标系有且只有一个,且是唯一不变的,其坐标原点在View的左上角,从坐标原点向右为x轴的正半轴,从坐标原点向下为y轴的正半轴。


Canvas绘制坐标系

Canvas的drawXXX方法中传入的各种坐标指的都是绘图坐标系中的坐标,而非Canvas坐标系中的坐标。默认情况下,绘图坐标系与Canvas坐标系完全重合,即初始状况下,绘图坐标系的坐标原点也在View的左上角,从原点向右为x轴正半轴,从原点向下为y轴正半轴。但不同于Canvas坐标系,绘图坐标系并不是一成不变的,可以通过调用Canvas的translate方法平移坐标系,可以通过Canvas的rotate方法旋转坐标系,还可以通过Canvas的scale方法缩放坐标系,而且需要注意的是,translate、rotate、scale的操作都是基于当前绘图坐标系的,而不是基于Canvas坐标系,一旦通过以上方法对坐标系进行了操作之后,当前绘图坐标系就变化了,以后绘图都是基于更新的绘图坐标系了。也就是说,真正对我们绘图有用的是绘图坐标系而非Canvas坐标系

//绘制坐标系
    protected void onDraw(Canvas canvas){
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(20);

        //用绿色画x轴,用蓝色画y轴

        //第一次绘制坐标轴
        paint.setColor(0xff00ff00);//绿色
        canvas.drawLine(0, 0, canvasWidth, 0, paint);//绘制x轴
        paint.setColor(0xff0000ff);//蓝色
        canvas.drawLine(0, 0, 0, canvasHeight, paint);//绘制y轴

        //对坐标系平移后,第二次绘制坐标轴
        canvas.translate(canvasWidth / 4, canvasWidth /4);//把坐标系向右下角平移
        paint.setColor(0xff00ff00);//绿色
        canvas.drawLine(0, 0, canvasWidth, 0, paint);//绘制x轴
        paint.setColor(0xff0000ff);//蓝色
        canvas.drawLine(0, 0, 0, canvasHeight, paint);//绘制y轴

        //再次平移坐标系并在此基础上旋转坐标系,第三次绘制坐标轴
        canvas.translate(canvasWidth / 4, canvasWidth / 4);//在上次平移的基础上再把坐标系向右下角平移
        canvas.rotate(30);//基于当前绘图坐标系的原点旋转坐标系
        paint.setColor(0xff00ff00);//绿色
        canvas.drawLine(0, 0, canvasWidth, 0, paint);//绘制x轴
        paint.setColor(0xff0000ff);//蓝色
        canvas.drawLine(0, 0, 0, canvasHeight, paint);//绘制y轴
    }

这里写图片描述

第一次绘制绘图坐标系时,绘图坐标系默认情况下和Canvas坐标系重合,所以绘制出的坐标系紧贴View的上侧和左侧;
第二次首先将坐标轴向右下角平移了一段距离,然后绘制出的坐标系也就整体向右下角平移了;
第三次再次向右下角平移,并旋转了30度,图上倾斜的坐标系即最后的绘图坐标系。


Canvas API中的相关方法

drawARGB(画布颜色)

Canvas中的drawARGB可以用来对整个Canvas以某种统一的颜色整体绘制,四个参数分别是Alpha、Red、Green、Blue,取值都是0-255。
使用代码如下:

canvas.drawARGB(255, 139, 197, 186);

这里写图片描述


drawText(文字绘制)

Canvas中用drawText方法绘制文字,代码如下所示:

private void drawText(Canvas canvas){
        int canvasWidth = canvas.getWidth();
        int halfCanvasWidth = canvasWidth / 2;
        float textHeight = 30f;
       float translateY = textHeight;

        //绘制正常文本
        canvas.save();
        canvas.translate(0, translateY);
        canvas.drawText("正常绘制文本", 0, 0, paint);
        canvas.restore();
        translateY += textHeight * 2;

        //绘制绿色文本
        paint.setColor(0xff00ff00);//设置字体为绿色
        canvas.save();
        canvas.translate(0, translateY);//将画笔向下移动
        canvas.drawText("绘制绿色文本", 0, 0, paint);
        canvas.restore();
        paint.setColor(0xff000000);//重新设置为黑色
        translateY += textHeight * 2;

        //设置左对齐
        paint.setTextAlign(Paint.Align.LEFT);//设置左对齐
        canvas.save();
        canvas.translate(halfCanvasWidth, translateY);
        canvas.drawText("左对齐文本", 0, 0, paint);
        canvas.restore();
        translateY += textHeight * 2;

        //设置居中对齐
        paint.setTextAlign(Paint.Align.CENTER);//设置居中对齐
        canvas.save();
        canvas.translate(halfCanvasWidth, translateY);
        canvas.drawText("居中对齐文本", 0, 0, paint);
        canvas.restore();
        translateY += textHeight * 2;

        //设置右对齐
        paint.setTextAlign(Paint.Align.RIGHT);//设置右对齐
        canvas.save();
        canvas.translate(halfCanvasWidth, translateY);
        canvas.drawText("右对齐文本", 0, 0, paint);
        canvas.restore();
        paint.setTextAlign(Paint.Align.LEFT);//重新设置为左对齐
        translateY += textHeight * 2;

        //设置下划线
        paint.setUnderlineText(true);//设置具有下划线
        canvas.save();
        canvas.translate(0, translateY);
        canvas.drawText("下划线文本", 0, 0, paint);
        canvas.restore();
        paint.setUnderlineText(false);//重新设置为没有下划线
        translateY += textHeight * 2;

        //绘制加粗文字
        paint.setFakeBoldText(true);//将画笔设置为粗体
        canvas.save();
        canvas.translate(0, translateY);
        canvas.drawText("粗体文本", 0, 0, paint);
        canvas.restore();
        paint.setFakeBoldText(false);//重新将画笔设置为非粗体状态
        translateY += textHeight * 2;

        //文本绕绘制起点顺时针旋转
        canvas.save();
        canvas.translate(0, translateY);
        canvas.rotate(20);
        canvas.drawText("文本绕绘制起点旋转20度", 0, 0, paint);
        canvas.restore();
    }
这里写图片描述

save() : 用来保存Canvas的状态,save()方法之后的代码,可以调用Canvas的平移、放缩、旋转、裁剪等操作!
restore():用来恢复Canvas之前保存的状态(可以想成是保存坐标轴的状态),防止save()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响,通过该方法可以避免连带的影响(或者简单理解当调用canvas.restore()后坐标轴恢复到canvas.save()之前的状态)

SaveLayer(图层)

private void drawLayer(Canvas canvas) {
        int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
                        | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG
                       | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
        canvas.drawColor(Color.WHITE);
        canvas.translate(10, 10);
        paint.setColor(Color.RED);
        canvas.drawCircle(75, 75, 75, paint);
        //图层大小
        canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, LAYER_FLAGS); //入栈
        canvas.drawARGB(255, 139, 197, 186);
        paint.setColor(Color.BLUE);
        canvas.drawCircle(125, 125, 75, paint);
        canvas.restore();


        /***************上面去掉saveLayerAlpha方法**********************/
        paint.setColor(Color.RED);
        canvas.drawCircle(300, 75, 75, paint);
        paint.setColor(Color.BLUE);
        canvas.drawCircle(350, 125, 75, paint);

    }


画一个蓝色圆是在这个layer中画的,透明度为0×88,和之前画红色圆的不是同一个layer层。在canvas.restore()被保存的layer就在红色圆layer上面了

saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags)


drawPoint(点绘制)

Canvas中用drawPoint方法绘制点,代码如下所示:

private void drawPoint(Canvas canvas) {
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        int x = canvasWidth / 2;
        int deltaY = canvasHeight / 3;
        int y = deltaY / 2;
        paint.setColor(0xff8bc5ba);//设置颜色
        paint.setStrokeWidth(50);//设置线宽,如果不设置线宽,无法绘制点

        //绘制Cap为BUTT的点
        paint.setStrokeCap(Paint.Cap.BUTT);
        canvas.drawPoint(x, y, paint);

        //绘制Cap为ROUND的点
        canvas.translate(0, deltaY);
        paint.setStrokeCap(Paint.Cap.ROUND);
        canvas.drawPoint(x, y, paint);

        //绘制Cap为SQUARE的点
        canvas.translate(0, deltaY);
        paint.setStrokeCap(Paint.Cap.SQUARE);
        canvas.drawPoint(x, y, paint);
    }

这里写图片描述

默认情况下Paint的getStrokeCap的返回值是Paint.Cap.BUTT,默认画出来的点就是一个正方形

  • Paint.Cap.BUTT
    当用BUTT作为帽端时,所绘制的线段恰好在起点终点位置处戛然而止,两端是方形,上图中第一条加粗的线段就是用BUTT作为帽端绘制的。

  • Paint.Cap.ROUND
    当用ROUND作为帽端时,所绘制的线段的两端端点会超出起点和终点一点距离,并且两端是圆形状,上图中第二条加粗的线段就是用ROUND作为帽端绘制的。

  • Paint.Cap.SQUARE
    当用SQUARE作为帽端时,所绘制的线段的两端端点也会超出起点和终点一点距离,两端点的形状是方形,上图中最后一条加粗的线段就是用SQUARE作为帽端绘制的。

drawLine(线段绘制)

Canvas通过drawLine方法绘制一条线段,通过drawLines方法绘制多段线,使用代码如下所示:

 private void drawLine(Canvas canvas) {
        int px = 500;
        int py = 500;
        Paint line = new Paint();
        line.setStrokeWidth(4);
        line.setColor(Color.RED);
        canvas.save();
        canvas.rotate(90, px / 2, py / 2);
        // 画一个向上的箭头
        canvas.drawLine(px / 2, 0, 0, py / 2, line); // 左边的斜杠
        canvas.drawLine(px / 2, 0, px, py / 2, line);// 右边的斜杠
        canvas.drawLine(px / 2, 0, px / 2, py, line);// 垂直的竖杠
        canvas.restore();
        canvas.drawCircle(px - 100, py - 100, 50, line);
    }

drawRect(矩形绘制)

Canvas通过drawRect方法绘制矩形,使用代码如下所示:

private void drawRect(Canvas canvas){
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();

        //默认画笔的填充色是黑色
        int left1 = 10;
        int top1 = 10;
        int right1 = canvasWidth / 3;
        int bottom1 = canvasHeight /3;
        canvas.drawRect(left1, top1, right1, bottom1, paint);

        //修改画笔颜色
        paint.setColor(0xff8bc5ba);//A:ff,R:8b,G:c5,B:ba
        int left2 = canvasWidth / 3 * 2;
        int top2 = 10;
        int right2 = canvasWidth - 10;
        int bottom2 = canvasHeight / 3;
        canvas.drawRect(left2, top2, right2, bottom2, paint);
    }

这里写图片描述

drawRect(float left, float top, float right, float bottom, Paint paint),left和right表示矩形的左边和右边分别到绘图坐标系y轴正半轴的距离,top和bottom表示矩形的上边和下边分别到绘图坐标系x轴正半轴的距离。


drawCircle(圆形绘制)

Canvas中用drawCircle方法绘制圆形,使用代码如下所示:

private void drawCircle(Canvas canvas){
        paint.setColor(0xff8bc5ba);//设置颜色
        paint.setStyle(Paint.Style.FILL);//默认绘图为填充模式
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        int halfCanvasWidth = canvasWidth / 2;
        int count = 3;
        int D = canvasHeight / (count + 1);
        int R = D / 2;

        //绘制圆
        canvas.translate(0, D / (count + 1));
        canvas.drawCircle(halfCanvasWidth, R, R, paint);

        //通过绘制两个圆形成圆环
        //1. 首先绘制大圆
        canvas.translate(0, D + D / (count + 1));
        canvas.drawCircle(halfCanvasWidth, R, R, paint);
        //2. 然后绘制小圆,让小圆覆盖大圆,形成圆环效果
        int r = (int)(R * 0.75);
        paint.setColor(0xffffffff);//将画笔设置为白色,画小圆
        canvas.drawCircle(halfCanvasWidth, R, r, paint);

        //通过线条绘图模式绘制圆环
        canvas.translate(0, D + D / (count + 1));
        paint.setColor(0xff8bc5ba);//设置颜色
        paint.setStyle(Paint.Style.STROKE);//绘图为线条模式
        float strokeWidth = (float)(R * 0.25);
        paint.setStrokeWidth(strokeWidth);
        canvas.drawCircle(halfCanvasWidth, R, R, paint);
    }

这里写图片描述


drawCircle (float cx, float cy, float radius, Paint paint),在使用时需要传入圆心的坐标以及半径,当然还有画笔Paint对象。

当我们在调用drawCircle、drawOval、drawArc、drawRect等方法时,我们既可以绘制对应图形的填充面,也可以只绘制该图形的轮廓线,控制的关键在于画笔Paint中的style。Paint通过setStyle方法设置要绘制的类型,style有取三种值:Paint.Style.FILL、Paint.Style.STROKE和Paint.Style.FILL_AND_STROKE。

         当style为FILL时,绘制是填充面,FILL是Paint默认的style;

         当style为STROKE时,绘制的是图形的轮廓线;

         当style为FILL_AND_STROKE时,同时绘制填充面和轮廓线,不过这种情况用的不多,因为填充面和轮廓线是用同一种颜色绘制的,区分不出轮廓线的效果。


drawOval(椭圆绘制)

Canvas中提供了drawOval方法绘制椭圆,其使用代码如下所示:

private void drawOval(Canvas canvas){
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        float quarter = canvasHeight / 4;
        float left = 10 ;
        float top = 0;
        float right = canvasWidth - left;
        float bottom= quarter;
        RectF rectF = new RectF(left, top, right, bottom);

        //绘制椭圆形轮廓线
        paint.setStyle(Paint.Style.STROKE);//设置画笔为画线条模式
        paint.setStrokeWidth(2);//设置线宽
        paint.setColor(0xff8bc5ba);//设置线条颜色
        canvas.translate(0, quarter / 4);
        canvas.drawOval(rectF, paint);

        //绘制椭圆形填充面
        paint.setStyle(Paint.Style.FILL);//设置画笔为填充模式
        canvas.translate(0, (quarter + quarter / 4));
        canvas.drawOval(rectF, paint);

        //画两个椭圆,形成轮廓线和填充色不同的效果
        canvas.translate(0, (quarter + quarter / 4));
        //1. 首先绘制填充色
        paint.setStyle(Paint.Style.FILL);//设置画笔为填充模式
        canvas.drawOval(rectF, paint);//绘制椭圆形的填充效果
        //2. 将线条颜色设置为蓝色,绘制轮廓线
        paint.setStyle(Paint.Style.STROKE);//设置画笔为线条模式
        paint.setColor(0xff0000ff);//设置填充色为蓝色
        canvas.drawOval(rectF, paint);//设置椭圆的轮廓线
    }

这里写图片描述

drawOval (RectF oval, Paint paint),RectF有四个字段,分别是left、top、right、bottom,

这四个值对应了椭圆的左、上、右、下四个点到相应坐标轴的距离,具体来说,left和right表示椭圆的最左侧的点和最右侧的点到绘图坐标系的y轴的距离,top和bottom表示椭圆的最顶部的点和最底部的点到绘图坐标系的x轴的距离,这四个值就决定了椭圆的形状,right与left的差值即为椭圆的长轴,bottom与top的差值即为椭圆的短轴,如下图所示:
这里写图片描述

drawArc(弧绘制)

Canvas中提供了drawArc方法用于绘制弧,这里的弧指两种:弧面和弧线,弧面即用弧围成的填充面,弧线即为弧面的轮廓线。其使用代码如下所示:

private void drawArc(Canvas canvas){
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        int count = 5;
        float ovalHeight = canvasHeight / (count + 1);
        float left = 10;
        float top = 0;
        float right = canvasWidth - left;
        float bottom= ovalHeight;
        RectF rectF = new RectF(left, top, right, bottom);

        paint.setStrokeWidth(2);//设置线宽
        paint.setColor(0xff8bc5ba);//设置颜色
        paint.setStyle(Paint.Style.FILL);//默认设置画笔为填充模式

        //绘制用drawArc绘制完整的椭圆
        canvas.translate(0, ovalHeight / count);
        canvas.drawArc(rectF, 0, 360, true, paint);

        //绘制椭圆的四分之一,起点是钟表的3点位置,从3点绘制到6点的位置
        canvas.translate(0, (ovalHeight + ovalHeight / count));
        canvas.drawArc(rectF, 0, 90, true, paint);

        //绘制椭圆的四分之一,将useCenter设置为false
        canvas.translate(0, (ovalHeight + ovalHeight / count));
        canvas.drawArc(rectF, 0, 90, false, paint);

        //绘制椭圆的四分之一,只绘制轮廓线
        paint.setStyle(Paint.Style.STROKE);//设置画笔为线条模式
        canvas.translate(0, (ovalHeight + ovalHeight / count));
        canvas.drawArc(rectF, 0, 90, true, paint);

        //绘制带有轮廓线的椭圆的四分之一
        //1. 先绘制椭圆的填充部分
        paint.setStyle(Paint.Style.FILL);//设置画笔为填充模式
        canvas.translate(0, (ovalHeight + ovalHeight / count));
        canvas.drawArc(rectF, 0, 90, true, paint);
        //2. 再绘制椭圆的轮廓线部分
        paint.setStyle(Paint.Style.STROKE);//设置画笔为线条模式
        paint.setColor(0xff0000ff);//设置轮廓线条为蓝色
        canvas.drawArc(rectF, 0, 90, true, paint);
    }

这里写图片描述

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

  • oval是RecF类型的对象,其定义了椭圆的形状。
  • startAngle指的是绘制的起始角度,钟表的3点位置对应着0度,如果传入的startAngle小于0或者大于等于360,那么用startAngle对360进行取模后作为起始绘制角度。
  • sweepAngle指的是从startAngle开始沿着钟表的顺时针方向旋转扫过的角度。如果sweepAngle大于等于360,那么会绘制完整的椭圆弧。如果sweepAngle小于0,那么会用sweepAngle对360进行取模后作为扫过的角度。
  • useCenter是个boolean值,如果为true,表示在绘制完弧之后,用椭圆的中心点连接弧上的起点和终点以闭合弧;如果值为false,表示在绘制完弧之后,弧的起点和终点直接连接,不经过椭圆的中心点。

drawPath(路径绘制)

Canvas通过drawPath方法可以绘制Path。那Path是什么呢?Path致以过来是路径的意思,在Android中,Path是一种线条的组合图形,其可以由直线、二次曲线、三次曲线、椭圆的弧等组成。Path既可以画线条,也可以画填充面。其使用代码如下所示:

private void drawPath(Canvas canvas){
        int canvasWidth = canvas.getWidth();
        int deltaX = canvasWidth / 4;
        int deltaY = (int)(deltaX * 0.75);

        paint.setColor(0xff8bc5ba);//设置画笔颜色
        paint.setStrokeWidth(4);//设置线宽

        /*--------------------------用Path画填充面-----------------------------*/
        paint.setStyle(Paint.Style.FILL);//设置画笔为填充模式
        Path path = new Path();
        //向Path中加入Arc
        RectF arcRecF = new RectF(0, 0, deltaX, deltaY);
        path.addArc(arcRecF, 0, 135);
        //向Path中加入Oval
        RectF ovalRecF = new RectF(deltaX, 0, deltaX * 2, deltaY);
        path.addOval(ovalRecF, Path.Direction.CCW);
        //向Path中添加Circle
        path.addCircle((float)(deltaX * 2.5), deltaY / 2, deltaY / 2, Path.Direction.CCW);
        //向Path中添加Rect
        RectF rectF = new RectF(deltaX * 3, 0, deltaX * 4, deltaY);
        path.addRect(rectF, Path.Direction.CCW);
        canvas.drawPath(path, paint);

        /*--------------------------用Path画线--------------------------------*/
        paint.setStyle(Paint.Style.STROKE);//设置画笔为线条模式
        canvas.translate(0, deltaY * 2);
        Path path2 = path;
        canvas.drawPath(path2, paint);

        /*-----------------使用lineTo、arcTo、quadTo、cubicTo画线--------------*/
        paint.setStyle(Paint.Style.STROKE);//设置画笔为线条模式
        canvas.translate(0, deltaY * 2);
        Path path3 = new Path();
        //用pointList记录不同的path的各处的连接点
        List<Point> pointList = new ArrayList<Point>();
        //1. 第一部分,绘制线段
        path3.moveTo(0, 0);
        path3.lineTo(deltaX / 2, 0);//绘制线段
        pointList.add(new Point(0, 0));
        pointList.add(new Point(deltaX / 2, 0));
        //2. 第二部分,绘制椭圆右上角的四分之一的弧线
        RectF arcRecF1 = new RectF(0, 0, deltaX, deltaY);
        path3.arcTo(arcRecF1, 270, 90);//绘制圆弧
        pointList.add(new Point(deltaX, deltaY / 2));
        //3. 第三部分,绘制椭圆左下角的四分之一的弧线
        //注意,我们此处调用了path的moveTo方法,将画笔的移动到我们下一处要绘制arc的起点上
        path3.moveTo(deltaX * 1.5f, deltaY);
        RectF arcRecF2 = new RectF(deltaX, 0, deltaX * 2, deltaY);
        path3.arcTo(arcRecF2, 90, 90);//绘制圆弧
        pointList.add(new Point((int)(deltaX * 1.5), deltaY));
        //4. 第四部分,绘制二阶贝塞尔曲线
        //二阶贝塞尔曲线的起点就是当前画笔的位置,然后需要添加一个控制点,以及一个终点
        //再次通过调用path的moveTo方法,移动画笔
        path3.moveTo(deltaX * 1.5f, deltaY);
        //绘制二阶贝塞尔曲线
        path3.quadTo(deltaX * 2, 0, deltaX * 2.5f, deltaY / 2);
        pointList.add(new Point((int)(deltaX * 2.5), deltaY / 2));
        //5. 第五部分,绘制三阶贝塞尔曲线,三阶贝塞尔曲线的起点也是当前画笔的位置
        //其需要两个控制点,即比二阶贝赛尔曲线多一个控制点,最后也需要一个终点
        //再次通过调用path的moveTo方法,移动画笔
        path3.moveTo(deltaX * 2.5f, deltaY / 2);
        //绘制三阶贝塞尔曲线
        path3.cubicTo(deltaX * 3, 0, deltaX * 3.5f, 0, deltaX * 4, deltaY);
        pointList.add(new Point(deltaX * 4, deltaY));

        //Path准备就绪后,真正将Path绘制到Canvas上
        canvas.drawPath(path3, paint);

        //最后绘制Path的连接点,方便我们大家对比观察
        paint.setStrokeWidth(10);//将点的strokeWidth要设置的比画path时要大
        paint.setStrokeCap(Paint.Cap.ROUND);//将点设置为圆点状
        paint.setColor(0xff0000ff);//设置圆点为蓝色
        for(Point p : pointList){
            //遍历pointList,绘制连接点
            canvas.drawPoint(p.x, p.y, paint);
        }
    }

这里写图片描述

Path对象还有很多xxTo方法,比如lineTo、arcTo、quadTo、cubicTo等,通过这些方法,我们可以方便的从画笔位置绘制到指定坐标的连续线条,如上图中最后一行的几个线状图形所示。我们用了lineTo、arcTo、quadTo、cubicTo这四种方法画了五段线条,下面会解释,并且单独通过调用drawPoint画出了每段线条的两个端点,方便大家观察。

  • moveTo方法用于设置下一个线条的起始点,可以认为是移动了画笔,但说移动画笔不严格,后面会解释,此处大家暂且这么理解。

  • lineTo的方法签名是public void lineTo (float x, float y),Path的lineTo方法会从当前画笔的位置到我们指定的坐标构建一条线段,然后将其添加到Path对象中,如上图中最后一行图形中的第一条线段所示。

  • arcTo的方法签名是public void arcTo (RectF oval, float startAngle, float sweepAngle),oval、startAngle与sweepAngle的参数与之前提到的darwArc方法对应的形参意义相同,在此不再赘述。Path的arcTo方法会构建一条弧线并添加到Path对象中,如上图中最后一行图形中的第二条和第三条线状图形所示,这两条弧线都是通过Path的arcTo方法添加的。

  • quadTo是用来画二阶贝塞尔曲线的,即抛物线,其方法签名是public void quadTo (float x1, float y1, float x2, float y2),如果对贝塞尔曲线的相关概念不了解,推荐大家读一下博文《贝塞尔曲线初探》 。下面借用该博文中的一张图说一下二阶贝塞尔曲线:
    这里写图片描述
    二阶贝塞尔曲线的绘制一共需要三个点,一个起点,一个终点,还要有一个中间的控制点。我们画笔的位置就相当于上图中P0的位置,quadTo中的前两个参数x1和y1指定了控制点P1的坐标,后面两个参数x2和y2指定了终点P2的坐标。上图中最后一行的第四个线状图形就是用quadTo绘制的二阶贝塞尔曲线。

  • cubicTo跟quadTo类似,不过是用来画三阶贝塞尔曲线的,其方法签名是public void cubicTo (float x1, float y1, float x2, float y2, float x3, float y3)。我们还是借用一下上述博文《贝塞尔曲线初探》中的另一张图片来解释一下三阶贝塞尔曲线:
    这里写图片描述
    三阶贝塞尔曲线的绘制需要四个点,一个起点,一个终点,以及两个中间的控制点,也就是说它比二阶贝塞尔曲线要多一个控制点。我们画笔的位置就相当于上图中P0的位置,cubicTo中的前两个参数x1和y1指定了第一个控制点P1的坐标,参数x2和y2指定了第二个控制点P2的坐标,最后两个参数x3和y3指定了终点P3的坐标。上图中最后一行的最后一个线状图形就是用cubicTo绘制的三阶贝塞尔曲线。


drawBitmap(Bitmap绘制)

Canvas中提供了drawBitmap方法用于绘制Bitmap,其使用代码如下所示:

private void drawBitmap(Canvas canvas){
        BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.mipmap.ic_launcher);
        Bitmap bitmap = bitmapDrawable.getBitmap();
        //如果bitmap不存在,那么就不执行下面的绘制代码
        if(bitmap == null){
            return;
        }

        //直接完全绘制Bitmap
        canvas.drawBitmap(bitmap, 0, 0, paint);

        //绘制Bitmap的一部分,并对其拉伸
        //srcRect定义了要绘制Bitmap的哪一部分
        Rect srcRect = new Rect();
        srcRect.left = 0;
        srcRect.right = bitmap.getWidth();
        srcRect.top = 0;
        srcRect.bottom = (int)(0.33 * bitmap.getHeight());
        float radio = (float)(srcRect.bottom - srcRect.top)  / bitmap.getWidth();
        //dstRecF定义了要将绘制的Bitmap拉伸到哪里
        RectF dstRecF = new RectF();
        dstRecF.left = 0;
        dstRecF.right = canvas.getWidth();
        dstRecF.top = bitmap.getHeight();
        float dstHeight = (dstRecF.right - dstRecF.left) * radio;
        dstRecF.bottom = dstRecF.top + dstHeight;
        canvas.drawBitmap(bitmap, srcRect, dstRecF, paint);
    }

这里写图片描述

public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)

该方法有两个功能:1.只绘制原有bitmap对象的一部分,2.还可以将要绘制的bitmap缩放到指定的区域。

  • 只绘制原有bitmap对象的一部分
    我们知道Bitmap是一个矩形,其是有宽度和高度的,也就说以bitmap对象本身作为坐标系(原点在bitmap左上角),我们可以构建一个Rect对象,如果满足left为0,top为0,right为bitmap的宽度,bottom为bitmap的高度,那么就说名我们要绘制整个Bitmap。但是有时候我们只想绘制Bitmap的一部分,例如我们上面的图中所示,我们想只绘制Android图像的头部区域怎么办呢?办法是我们构建一个Rect对象,定义我们要绘制Bitmap的哪些部位。
    比如我们通过代码srcRect.bottom = (int)(0.33 * bitmap.getHeight())指定了我们只绘制bitmap对象头部1/3的位置,即Android图像的头部,这样我们用该指定的srcRect绘制bitmap时只绘制了其头部位置。需要特别注意的是,srcRect中left、top、right、bottom的值都是以Bitmap本身的局部坐标系为基础的。

  • 将要绘制的bitmap缩放到指定的区域
    有时候我们需要将原有的bitmap进行放大或缩小,如上图所示,我们将原有图片放大了,这怎么做呢?我们需要指定RectF类型的参数dstRectF,以便告诉Android将srcRect中定义的bitmap缩放到哪里。即Android会将srcRect中定义的bitmap缩放到dstRectF区域范围内。需要注意的是,此处的dstRecF是绘图坐标系中的坐标,不是Bitmap本身的局部坐标系。我们在代码中保证了dstRecF的长宽比与srcRect中的长宽比相同,这样不会导致图片长宽比例变形,效果见上图中的第二个放大的图形。






参考博文:http://blog.csdn.net/iispring/article/details/49770651

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值