canvas 用法详解

本文介绍了Canvas坐标系和绘图坐标系的区别。Canvas坐标系固定不变,原点位于View左上角。绘图坐标系可变,通过translate、rotate、scale方法调整。在变换坐标系后,使用save()和restore()可以保存和恢复绘图状态,确保变换的叠加效果。文字绘制从左下角开始。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


孙群        点击打开链接



Canvas绘图中牵扯到两种坐标系:Canvas坐标系与绘图坐标系。

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

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

 

private void drawText(Canvas canvas){
        int canvasWidth = canvas.getWidth();
        int halfCanvasWidth = canvasWidth / 2;
        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();
    }


我们在上面的代码中将canvas.translate()和canvas.rotate()放到了canvas.save()和canvas.restore()之间,这样做的好处是,在canvas.save()调用时,将当前坐标系保存下来,将当前坐标系的矩阵Matrix入栈保存,然后通过translate或rotate等对坐标系进行变换,然后进行绘图,绘图完成后,我们通过调用canvas.restore()将之前保存的Matrix出栈,这样就将当前绘图坐标系恢复到了canvas.save()执行的时候状态。如果熟悉OpenGL开发,对这种模式应该很了解。


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

        paint.setStrokeWidth(2 * density);//设置线宽
        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);
    }



对canvas进行变换是会叠加的。


所以为了绘图坐标系要向每次和Canvas坐标系重合,需要在对canvas变换前保存图层,完成后恢复图层。

 

如果为了一致叠加前面的变换,那就没必要保存再恢复canvas了。


文字是从文字的左下角开始绘制的。

            如图:

                  






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值