2024年Android Matrix矩阵,Android面试知识点梳理

分享读者

作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括腾讯,以及字节跳动,阿里,华为,小米,等一线互联网公司主流架构技术。

腾讯T3架构师学习专题资料

如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!

我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

用A的第1行各个数与B的第3列各个数对应相乘后加起来,就是乘法结果中第1行第3列的数;

依次求出第二行和第三行即可。

假设3*3矩阵与3*2矩阵乘法种的项分别为:a11  a12  a13 a21  a22  a23  a31  a32  a33 和b11  b12  b21  b22  b23,

则新的得到的矩阵:第一项为c11=a11*c11+a12*c21+a13*c31剩余项依次类推即可。

2、Matrix矩阵

==========

根据文章1而写

2.1、概述


Matrix是Android中用于处理图形的一个3*3的矩阵。

2.2、原理


先看看matrix的矩阵是什么样子的:

源码:

public static final int MSCALE_X = 0; //!< use with getValues/setValues

public static final int MSKEW_X = 1; //!< use with getValues/setValues

public static final int MTRANS_X = 2; //!< use with getValues/setValues

public static final int MSKEW_Y = 3; //!< use with getValues/setValues

public static final int MSCALE_Y = 4; //!< use with getValues/setValues

public static final int MTRANS_Y = 5; //!< use with getValues/setValues

public static final int MPERSP_0 = 6; //!< use with getValues/setValues

public static final int MPERSP_1 = 7; //!< use with getValues/setValues

public static final int MPERSP_2 = 8; //!< use with getValues/setValues

那么这个矩阵分别代表了什么呢,这里通过他们的名字可以看出,scale是缩放,skew是错切,trans是平移,persp代表透视(官方文档中,也没有详细讲解,透视在这里只做简单介绍)。这里需要把矩阵根据他们的作用划分为4块:

如上图所示,这四块区域各有作用。后面会详细讲解各个作用,先来看看这个矩阵是如何影响图像的。先看看屏幕的坐标系:

看上图,这里表示了屏幕的坐标系,其中的x,y轴是大家所熟知的,但是其实,一个物体他是存在于一个三维空间的,所以必然会有z轴。我们的屏幕,就像是一个窗口,透过它,我们看到了屏幕后面的世界,那里面有各种物体,我们看到的是映射在x,y平面上的一个投射图像。屏幕就像是一个镜头一样,将里面的物体映射到x,y平面上,成为一个二维的图像。那么如果,我们把屏幕这个镜头沿着z轴,拉远或者拉进,那么图像会有什么变化呢,肯定会变小或者变大。就好比坐在飞机上透过窗口看地面的汽车,和在地面上看到的大小是不同的。

结论就是,在屏幕上显示的像素,不仅仅有x,y坐标,其实还有z轴的影响。所以这里对应的像素描述由一个3行一列的矩阵来表示:

x,y分别代表x,y轴上的坐标,而1代表屏幕在z轴上的坐标为默认的。如果将1变大,那么屏幕会拉远, 图形会变小。

现在我们来看看matrix怎么作用于每个像素的值。这里需要用到矩阵的乘法,首先需要明确的是,矩阵的前乘和后乘是不相同的,也就是说不满足乘法交换律。

这里我们通过一个旋转变换来看看原理,其实一张图片围绕一个点旋转,也就是所有的点都围绕一个点旋转,所以只需要关注一个点的情况即可:

假定有一个点 ,相对坐标原点顺时针旋转后的情形,同时假定P点离坐标原点的距离为r,如下图:

那么就有:

换做矩阵运算就如下图:

同时,可以看到,上面的矩阵四块区域的切分也是因为矩阵乘法的操作决定的,由于这里的乘法运算中,左上角的四个值,可以和x,y值做乘法运算,所以可以影响到旋转等操作,而右上角的模块,只能做加法,所以只能影响到平移。右下角的模块主要管z轴,自然就可以进行等比的缩放了,左下角的模块一般不去动他,否则会把x,y值加入到z轴中来,会不可控。

3、基本方法分析

========

讲解完了matrix作用于像素点的原理之后,我们逐个讲解它的方法。

3.1、构造函数


public Matrix()

public Matrix(Matrix src)

构造函数有两个,第一个是直接创建一个单位矩阵,第二个是根据提供的矩阵创建一个新的矩阵(采用deep copy)

单位矩阵如下:

3.2、isIdentity与isAffine


public boolean isIdentity()//判断是否是单位矩阵

public boolean isAffine()//判断是否是仿射矩阵

是否是单位矩阵很简单,就不做讲解了,这里是否是仿射矩阵可能大家不好理解。

首先来看看什么是仿射变换。仿射变换其实就是二维坐标到二维坐标的线性变换,保持二维图形的“平直性”(即变换后直线还是直线不会打弯,圆弧还是圆弧)和“平行性”(指保持二维图形间的相对位置关系不变,平行线还是平行线,而直线上点的位置顺序不变),可以通过一系列的原子变换的复合来实现,原子变换就包括:平移、缩放、翻转、旋转和错切。这里除了透视可以改变z轴以外,其他的变换基本都是上述的原子变换,所以,只要最后一行是0,0,1则是仿射矩阵。

3.3、rectStaysRect


public boolean rectStaysRect()

判断该矩阵是否可以将一个矩形依然变换为一个矩形。当矩阵是单位矩阵,或者只进行平移,缩放,以及旋转90度的倍数的时候,返回true。

3.4、reset


public void reset()

重置矩阵为单位矩阵。

3.5、setTranslate


public void setTranslate(float dx, float dy)

设置平移效果,参数分别是x,y上的平移量。

效果图如下:

代码如下:

Matrix matrix = new Matrix();

canvas.drawBitmap(bitmap, matrix, paint);

matrix.setTranslate(100, 1000);

canvas.drawBitmap(bitmap, matrix, paint);

3.6、setScale


public void setScale(float sx, float sy, float px, float py)

public void setScale(float sx, float sy)

两个方法都是设置缩放到matrix中,sx,sy代表了缩放的倍数,px,py代表缩放的中心。这里跟上面比较类似不做讲解了。

3.7、setRotate


public void setRotate(float degrees, float px, float py)

public void setRotate(float degrees)

和上面类似,不再讲解。

3.8、setSinCos


public void setSinCos(float sinValue, float cosValue, float px, float py)

public void setSinCos(float sinValue, float cosValue)

这个方法乍一看可能有点蒙,其实在前面的原理中,我们讲解了一个旋转的例子,他最终的矩阵效果是这样的:

其实旋转,就是使用了这样的matrix,显而易见,这里的参数就清晰了。

sinValue:对应图中的sin值

cosValue:对应cos值

px:中心的x坐标

py:中心的y坐标

看一个示例,我们把图像旋转90度,那么90度对应的sin和cos分别是1和0。

看代码如下:

Matrixmatrix = new Matrix();

matrix.setSinCos(1, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2);

canvas.drawBitmap(bitmap, matrix, paint);

3.9、setSkew


public void setSkew(float kx, float ky, float px, float py)

public void setSkew(float kx, float ky)

错切,这里kx,ky分别代表了x,y上的错切因子,px,py代表了错切的中心。不了解错切了在前面canvas变换中去查看,这里不再讲解。

3.10、setConcat


public boolean setConcat(Matrix a,Matrix b)

将当前matrix的值变为a和b的乘积,它的意义在下面的 进阶方法中来探讨。

4、进阶方法解析

============

上面的基本方法中,有关于变换的set方法都可以带来不同的效果,但是每个set都会把上个效果清除掉,例如依次调用了setSkew,setTranslate,那么最终只有setTranslate会起作用,那么如何才和将两种效果复合呢。Matrix给我们提供了很多方法。但是主要都是2类:

preXXXX:以pre开头,例如preTranslate

postXXXX:以post开头,例如postScale

他们分别代表了前乘,和后乘。看一段代码:

Matrix matrix = new Matrix();

matrix.setTranslate(100, 1000);

matrix.preScale(0.5f, 0.5f);

这里matrix前乘了一个scale矩阵,换算成数学式如下:

从上面可以看出,最终得出的matrix既包含了缩放信息也有平移信息。

后乘自然就是matrix在后面,而缩放矩阵在前面,由于矩阵前后乘并不等价,也就导致了他们的效果不同。我们来看看后乘的结果:

可以看到,结果跟上面不同,并且这也不是我们想要的结果,这里缩放没有更改,但是平移被减半了,换句话说,平移的距离也被缩放了。所以需要注意前后乘法的关系。

来看看他们对应的效果图:

前乘:

后乘:

可以明显看到,后乘的平移距离受了影响。

了解清除了前后乘的意义,在使用的过程中,多个效果的叠加时,一样要注意,否则效果达不到预期。

5、其他方法解析

========

matrix除了上面的方法外,还有一些其他的方法,这里依次解析

5.1、setRectToRect


public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf)

将rect变换成rect,上面的rectStaysRect已经说过,要保持rect只能做缩放平移和选择90度的倍数,那么这里其实也是一样,只是这几种变化,这里通过stf参数来控制。

ScaleToFit 有如下四个值:

FILL: 可能会变换矩形的长宽比,保证变换和目标矩阵长宽一致。

START:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。左上对齐。

CENTER: 保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。

END:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。右下对齐。

这里使用谷歌的api demo的图片作为例子:

5.2、setPolyToPoly


public boolean setPolyToPoly(float[] src, int srcIndex,float[] dst, int dstIndex,int pointCount)

通过指定的0-4个点,原始坐标以及变化后的坐标,来得到一个变换矩阵。如果指定0个点则没有效果。

下面通过例子分别说明1到4个点的可以达到的效果:

5.2.1、1个点,平移

只指定一个点,可以达到平移效果:

代码如下:

float[] src = {0, 0};

int DX = 300;

float[] dst = {0 + DX, 0 + DX};

matrix.setPolyToPoly(src, 0, dst, 0, 1);

canvas.drawBitmap(bitmap, matrix, paint);

5.2.2、2个点,旋转或者缩放

两个点,可以达到旋转效果或者缩放效果,缩放比较简单,这里我们来看旋转效果,一个点指定中心,一点指出旋转的效果

代码如下:

int bw = bitmap.getWidth();

int bh = bitmap.getHeight();

float[] src = {bw / 2, bh / 2, bw, 0};

float[] dst = {bw / 2, bh / 2, bw / 2 + bh / 2, bh / 2 + bw / 2};

matrix.setPolyToPoly(src, 0, dst, 0, 2);

canvas.drawBitmap(bitmap, matrix, paint);

尾声

一转眼时间真的过的飞快。我们各奔东西,也各自踏上了自己的旅途,但是即使多年不见,也因为这份情谊我们依旧如从前那般“亲密”。不忘初心方得始终。加油吧,程序员们,在我看来35岁,40岁从来不是危机,只要永远不要忘记自己为何踏上征程!

为了让更多在学习中或者最近要准备面试的朋友们看到这篇文章,希望你们能多多评论,点赞+转发!

再次感谢所有给我提供过题目的朋友们,感谢一路有你!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ap.getWidth();

int bh = bitmap.getHeight();

float[] src = {bw / 2, bh / 2, bw, 0};

float[] dst = {bw / 2, bh / 2, bw / 2 + bh / 2, bh / 2 + bw / 2};

matrix.setPolyToPoly(src, 0, dst, 0, 2);

canvas.drawBitmap(bitmap, matrix, paint);

尾声

一转眼时间真的过的飞快。我们各奔东西,也各自踏上了自己的旅途,但是即使多年不见,也因为这份情谊我们依旧如从前那般“亲密”。不忘初心方得始终。加油吧,程序员们,在我看来35岁,40岁从来不是危机,只要永远不要忘记自己为何踏上征程!

为了让更多在学习中或者最近要准备面试的朋友们看到这篇文章,希望你们能多多评论,点赞+转发!

再次感谢所有给我提供过题目的朋友们,感谢一路有你!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值