自定义view绘图篇--Canvas的变换

画布的相关操作也是十分重要的,上一篇《自定义view绘图篇–Paint与Canvas》的总结使我们对绘图有了一些基本的概念,并且能够绘制了基本的几何图形,本节继续深入,探讨画布的相关操作。

本节要点

在这里插入图片描述

一、画布平移 (translate)

1、画布须知

画布的默认大小、默认坐标系和你的自定义view的大小、自定义view的坐标系一致!!!
画布的默认大小、默认坐标系和你的自定义view的大小、自定义view的坐标系一致!!!
画布的默认大小、默认坐标系和你的自定义view的大小、自定义view的坐标系一致!!!
重要的事说三遍哈。。。
ps:画布的坐标系我们看成虚拟的就行,他只影响你的作画。

(1)栗子
在这里插入图片描述
在这里插入图片描述

(2)佐证

在这里插入图片描述

2、画布的平移操作
  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.GRAY);

        paint.setColor(Color.RED);
        canvas.drawCircle(0, 0, 100, paint); // 坐标原点为圆心画圆

        paint.setColor(Color.BLUE);
        canvas.translate(100, 100); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
        canvas.drawCircle(0, 0, 100, paint); // 画布圆心画圆

    }

在这里插入图片描述

(2)画出平移后的坐标系

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        paint.setColor(Color.YELLOW);
        canvas.translate(100, 100); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
        canvas.drawCircle(0, 0, 100, paint); // 画布圆心画圆

        paint.setColor(Color.RED);
        canvas.drawLines(lines, paint);

    }

在这里插入图片描述

如上:我们可以虚拟出画布的坐标,红线向右为正,向下为正。

二、画布缩放 (scale)

1、方法

在这里插入图片描述

方法1:

sx 、sy 为x轴y轴缩放比例。

方法2:

sx 、sy 为x轴y轴缩放比例。
px、py 为中心点的坐标(控制中心点的位置)

2、缩放参数sx 、sy 的取值范围

sx 、sy取值范围 (-∞,+∞)
1、缩放比例和view动画的缩放比例取值类似,就是缩放的倍数
2、注意当为负数时,代表缩放相应的倍数后,再沿着中心翻转
3、数值为0,图案消失

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        paint.setColor(Color.YELLOW);
        canvas.translate(100, 100); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
        canvas.drawCircle(0, 0, 100, paint); // 画布圆心画圆

        paint.setColor(Color.RED);
        canvas.drawLines(lines, paint);

        paint.setColor(Color.RED);
        canvas.scale(.5f, .5f); //缩放画布为原来的一般
        canvas.drawCircle(0, 0, 100, paint);// 画圆

    }

在这里插入图片描述

3、缩放经典案例
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(300, 300); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点

        paint.setColor(Color.RED);
        canvas.drawLines(lines, paint); // 画个平移后画布的坐标系


        paint.setColor(Color.BLACK);
        canvas.drawCircle(0, 0, 200, paint); // 画布圆心画圆


        for (int i = 0; i < 30; i++) {
            canvas.scale(.9f, .9f); //缩放画布为原来的一般
            canvas.drawCircle(0, 0, 200, paint);// 画圆
        }
    }

在这里插入图片描述

注意:和平移一样,缩放是可以叠加的,如上每次把画布缩放为原来的0.9倍。循环30次即可得到上图。

三、画布旋转 (rotate)

1、方法
  public void rotate (float degrees)
  
  public final void rotate (float degrees, float px, float py)

方法1参数:degrees画布旋转角度
方法2参数:degrees画布旋转角度,px、py 指定画布的中心点。

2、简单的钟表时针刻度实战
   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(300, 300); //移动画布 使画布的坐标系圆心为view坐标系中的(300,300)这点

        paint.setColor(Color.RED);
        canvas.drawLines(lines, paint); // 画个平移后画布的坐标系


        paint.setColor(Color.BLACK);
        canvas.drawCircle(0, 0, 200, paint); // 画布圆心画圆


        for (int i = 0; i < 12; i++) {
            //画布相对上次旋转12次
            canvas.rotate(30);
            canvas.drawLine(0, 200, 0, 180, paint);
        }
        
    }

在这里插入图片描述

须知:和画布的平移、缩放一样,画布的旋转也是可叠加的
思路:
1、先画圆(这里半径设置200)
2、画一个0点的线(这里线长度为200-180=20)
3、让画布每次旋转30度,旋转12次即可
ps:没接触过canvas相关操作,给你个自定义时钟需求这些思路我们可能想不到,这里知识积累到后,自己就想摸索出来了。快乐啦。。。。

四、画布扭曲(错切、斜切) skew

1、正切回顾

在这里插入图片描述

2、方法
/**
     * Preconcat the current matrix with the specified skew.
     *
     * @param sx The amount to skew in X
     * @param sy The amount to skew in Y
     */
public void skew(float sx, float sy)

参数:
1、sx:将画布在x轴倾斜n°后的tan n°的值即 sx=tan n°
2、sy:将画布在y轴倾斜n°后的tan n°的值即 sy=tan n°
ps:比如我们sx参数填1.732 (根号3)就是x轴大约倾斜了60°

3、栗子
  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(300, 300); //1、移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点

        paint.setColor(Color.RED);
        canvas.drawLines(lines, paint); // 2、画个平移后画布的坐标系


        paint.setColor(Color.BLACK);
        canvas.drawRect(0, 0, 200,200, paint);  // 3、画个矩形

        paint.setColor(Color.GREEN);
        canvas.skew(1.732f,0);
        canvas.drawRect(0, 0, 200,200, paint);  // 4、扭曲画布后再画个矩形
    }

在这里插入图片描述

五 、画布的裁剪 (ClipXxx)

画布裁剪顾名思义就是在画布上裁剪出一块小的画布
具体的说就是利用ClipXxx相关的函数在画布上裁剪出 rect、Path、Region等。

1、ClipXxx相关的方法
boolean	clipPath(Path path)
boolean	clipPath(Path path, Region.Op op)
boolean	clipRect(Rect rect, Region.Op op)
boolean	clipRect(RectF rect, Region.Op op)
boolean	clipRect(int left, int top, int right, int bottom)
boolean	clipRect(float left, float top, float right, float bottom)
boolean	clipRect(RectF rect)
boolean	clipRect(float left, float top, float right, float bottom, Region.Op op)
boolean	clipRect(Rect rect)
boolean	clipRegion(Region region)
boolean	clipRegion(Region region, Region.Op op)

这里引用:自定义控件之绘图篇(四):canvas变换与操作-五的内容,由于api都差不多自己就不下啦,偷偷懒。。。。。

2、栗子
  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawColor(Color.GRAY); //互补背景设置为灰色

        canvas.clipRect(0,0,300,300);
        canvas.drawColor(Color.WHITE); // 裁剪的小画布设置为白色背景
        
        canvas.drawCircle(150,150,50,paint); //圆心为(150,150)半径为50 画圆
    }

在这里插入图片描述

六、画布的保存与恢复 (save、 restore)

前面的相关操作:旋转、平移、缩放、扭曲、等操作后是可以叠加的。比如我们把画布平移后,以后的绘制图案操作都是基于平移后的。这就比价不尽人意啦,我们想要下次还操作之前的画布呢?这是安卓提供了save和restore方法

1、方法
  • save() 保存当前状态,入栈。
  • restore()取出栈顶的状态
2、栗子:

(1)未进行状态恢复时

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawColor(Color.GRAY); //画布背景设置为灰色
        canvas.save(); // 1、保存下画布的状态 状态入栈

        canvas.clipRect(0,0,300,300); // 裁剪画布
        canvas.drawColor(Color.WHITE); // 画布设置为白色背景
        canvas.drawCircle(300,300,50,paint); // 基于裁剪过得画布内画圆
}

在这里插入图片描述

可以看出我们的操作是基于裁剪之后的画布(超出裁剪的区域绘制不出来的)

(2)恢复上次保存的状态

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawColor(Color.GRAY); //画布背景设置为灰色
        canvas.save(); // 1、保存下画布的状态 状态入栈

        canvas.clipRect(0,0,300,300); // 裁剪画布
        canvas.drawColor(Color.WHITE); // 画布设置为白色背景
        canvas.drawCircle(300,300,50,paint); // 基于裁剪过得画布内画圆

      
        //恢复裁剪之前保存的状态
        canvas.restore();
        canvas.drawCircle(300,300,50,paint); // 读取上次save时的画布状态

    }

在这里插入图片描述

3、注意

每次save就相当于状态入栈一次,具有多次save时,一定要注意你restore的状态是哪一次的。

小结

通过对画布的探讨总结,明白了一些技巧,比如自定义闹钟以后就有思路啦。。。知识在慢慢积累内心也有成就感!快乐啦马飞飞。。。。。溜溜球下篇见。

下一篇:自定义view绘图篇–Path

参考文章:

Canvas之画布操作

自定义控件之绘图篇(四):canvas变换与操作

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值