Android Matrix的理解

前言

Android绘制中最重要的要算Matrix类了,同时也是不太好理解的。以前也用过,但是掌握的也不是太好,刚好有时间好好的总结下。

一.基础

1.1 Matrix

Matrix既矩阵,数学里面很重要的工具,在安卓中用于做坐标转换,本篇博文主要记录一下Android中Matrix对于图片的preXXX,postXXX相关API的使用,对于矩阵的数学原理不做过多的深究。

Android关于Matrix最经典的一张图片:
Matrix
那么对于上图的总结:

  • 缩放(Scale)
    对应 MSCALE_XMSCALE_Y
  • 位移(Translate)
    对应 MTRANS_XMTRANS_Y
  • 错切(Skew)
    对应 MSKEW_XMSKEW_Y
  • 旋转(Rotate)
    旋转没有专门的数值来计算,Matrix 会通过计算缩放与错切来处理旋转。

1.2 使用Matrix的准备知识

完全了解图片的坐标原点概念,对于使用Matrix非常重要,对这个概念,有以下两点总结:

  • 所有的操作(旋转、平移、缩放、错切)默认都是以坐标原点为基准点的。
  • 之前操作的坐标系状态会保留,并且影响到后续状态。

举个栗子:

canvas.drawBitmap(mBitmap, 0, 0 , null);

图片会在画布的左上角绘制,此时原点即为画布的左上角,也是图片自身的左上角。
演示结果
红色箭头所指之处便是原点。
实际上坐标原点就是图片自身的左上角,对于这一点可以做个试验看一下:
试验代码:

private void drawMatrix(Canvas canvas){
		// 原图
        mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        // 从mBitmap中copy出来一张新的bitmap
        Bitmap newBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
        // 居中位置
        float px = (getWidth() - mBitmap.getWidth()) / 2.0f;
        float py = (getHeight() - mBitmap.getHeight()) / 2.0f;
        // 原图移动位置后再顺时针旋转90度
        mLocationMatrix.preTranslate(px, py);
        mLocationMatrix.preRotate(90);
        // draw原图和新图
        canvas.drawBitmap(mBitmap, mLocationMatrix, null);
        // 新图居中显示
        canvas.drawBitmap(newBitmap, px, py, null);
}

运行结果:
演示结果
通过运行结果,可以看出中间的图片确实是绕着自身的左上角顺时针旋转了90度。
有了上面的概念,就可以继续学习Matrix的preXXXpostXXX相关API了。

二.preXXX和postXXX

2.1 右乘和左乘

对于我而言,学习Matrix最为头疼的是搞清楚诸如preTranslate和postTranslate,preRotate和postRotate等相关API的前后执行顺序关系。

想要知道这个顺序关系,需要知道涉及矩阵的数学运算,矩阵的右乘和左乘。
直接给出这个运算规律,你需要记住这个规则
(重要)

// tips: 这里的M是原始矩阵,A是诸如平移,缩放等矩阵,M'是结果矩阵
preXXX  : 右乘, M' = M*A (右乘是因为A在右边)
postXXX : 左乘, M' = A*M (左乘是因为A在左边)

令:T=平移,R=旋转,S=缩放

  1. 全是preXXX相关API:
matrix.preTranslate(px, py);
matrix.preRotate(90);
matrix.preScale(0.5f, 0.5f);

根据上面的规则,则可以写成:
M’ = M * T * R * S (右乘)

  1. 全是postXXX相关API:
matrix.postTranslate(px, py);
matrix.postRotate(90);
matrix.postScale(0.5f, 0.5f);

M’ = S * R * T * M (左乘)

  1. 混合操作:
matrix.postTranslate(px, py);
matrix.preRotate(90);
matrix.preScale(0.5f, 0.5f);

M’ = T * M * R * S
不过对于写代码,不建议混合使用,应该要么用前乘,要么用后乘。

那么知道这个有啥用呢?
当我们通过以上规则得到诸如M’ = M * T * R * S结果后,只要去掉M不看,再从左到右的顺序执行,这样的执行顺序就是使用postXXX和preXXX相关API的前后执行顺序。

所以执行的顺序:

  • M’ = M * T * R * S的顺序就是先平移,再旋转,最后缩放。
  • M’ = S * R * T * M的顺序就是先缩放,再旋转,最后平移。

2.2 验证规律

最后验证一下这个规律:
下面的这段代码是想将图片移动到canvas中间,并且还需要图片倒立展示。

		mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
       	// 居中显示
        float px = (getWidth() - mBitmap.getWidth()) / 2.0f;
        float py = (getHeight() - mBitmap.getHeight()) / 2.0f;
        // 先preRote
        matrix.preRotate(180,
                mBitmap.getWidth() / 2.0f,
                mBitmap.getHeight() / 2.0f
        );
        // 后postTranslate
        matrix.postTranslate(px, py);
        canvas.drawBitmap(mBitmap, matrix, null);

上面的代码直观上给人的感觉是先旋转,再平移。实际上,根据上面的左乘和右乘的规律应该是:
M’ = T * M * R先平移到(px, py)的位置,最后按照图片中心点旋转180度。

运行结果:
在这里插入图片描述
成功的将图片居中并且倒立展示。

三.坐标原点

前面说了所有的操作(旋转、平移、缩放、错切)默认都是以坐标原点为基准点的
下面来验证下:

// 相对图片中心点旋转180度
matrix.preRotate(180, mBitmap.getWidth() / 2.0f, mBitmap.getHeight() / 2.0f);

运行结果:
在这里插入图片描述
matrix在被初始化的时候实际上是一个单位矩阵
在这里插入图片描述
可以看到2和5位置上的值是0,这就意味着没有移动,那么图片的出生地就是canvas的左上角,也就是图片的左上角。旋转的时候是按照图片的中点去旋转角度的。
所以在写代码的时候,如果图片已经平移到canvas的其他位置,同时还要图片旋转一定角度,那么直接对于图片的宽高各自一半进行旋转即可。
类似以下代码:

matrix.preTranslate(px, py);
matrix.preRotate(180, mBitmap.getWidth() / 2.0f, mBitmap.getHeight() / 2.0f
);

结束

掌握了矩阵的左乘和右乘和坐标原点之后,写起和matrix相关的代码,将会变得非常轻松。祝大家学习进步,早日上岸!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rockyou666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值