自定义View(十)Matrix 基础理论与使用
Matrix就是矩阵的意思,所有的控件中都有Matrix的身影。
Matrix是一个三阶矩阵,主要功能是坐标映射,数值变换,见下图
Matrix再讲下边的内容之间,先提前介绍一下下边用到的名词:
名词 | 解释 |
---|---|
单位矩阵 | 单位矩阵 |
M | 原始矩阵,没有变换之前的矩阵 |
A | 变换 |
M` | 结果矩阵 |
T | 平移变换 |
-T | 反向平移变换 |
R | 旋转变换 |
Matrix基本原理
Matrix的根本作用就是坐标的变化;基本变换有平移(translate),缩放(scale),旋转(skew),错切四种。
矩阵中各数据组合所指
矩阵中各数据组合所指
最后一行的数据透视使用在3D变换中
缩放(scale)
在进行缩放的时候需要变换(MSCALE_X,MSCALE_Y)这两个值,分别作用于x和y。
缩放
X=K1*X0
Y=K2*Y0
错切(skew)
错切需要变换(MSKEW_X,MSKEW_Y),分别作用于水平错切和垂直错切;
错切
X=X0+K1*Y0
Y=K2*X0+Y0
旋转(rotate)
当要旋转 θ角度的时候,博客中计算了一遍,讲了下边矩阵变换数据的来历,我看了一遍也记不住,还是及这个图来的快。。。。
旋转
平移(translate)
平移需要修改的是最后一列的前两个数据(MTRANS_X,MTRANS_Y),分别作用在x和y 上。
平移
总结
看了上边的几种变换,其实就是对应修改单位矩阵中的特定数值。比如说,要旋转,就要修改左上角四个数值,得到变换矩阵,拿变换矩阵跟原始矩阵相乘。平移,就是修改单位矩阵中最后一列的上边两个数值,如果你只想在x轴平移,那么只需要修改最后一列的第一个数据。看了上边的东西,大概知道矩阵作用了,可是矩阵该怎么在实际代码中使用呢?一步一步来
Matrix 矩阵复合原理
矩阵复合有三种,前乘(pre),后乘(post),设置(set)
为什么会有前乘和后乘的区别呢?
因为
矩阵乘法不满足交换律,即 AB ≠ BA
矩阵乘法满足结合律,即 (AB)C = A(BC)
矩阵与单位矩阵相乘结果不变,即 A * I = A
前乘(pre)
前乘就是原始矩阵在前边,变换矩阵在后边
M`=M*A
后乘(post)
后乘就是原始矩阵在后边,变换矩阵在前边
M`=S*A
设置(set)
设置不是矩阵的乘法,而是覆盖原来的矩阵,使用设置之后会对之前的操作有影响。
几个常见的错误结论:
1.pre 是顺序执行,post 是逆序执行
2.pre 是先执行,而 post 是后执行
其实前乘后乘执行的顺序,跟这句代码所在的位置没有关系。
下边将一个远博客中的例子。
我们想讲一个控件先平移到屏幕的中间,然后对控件做一系列缩放,错切,平移等等操作,最后我们再将控件平移回远位置。
上面的操作我们可以使用三种方法实现:
第一种前后两个平移全部使用前乘(pre)
Matrix matrix=new Matrix();
matrix.preTranslate(200,200);
matrix.preRotate(angle);
matrix.preTranslate(-200,-200);
M`=M*T*R-T
新实例化的矩阵就是单位矩阵,所以这里M为原始矩阵,所以上边的式子可以简化为
M`=*T*R-T
第二种前后两个平移全部使用后乘
Matrix matrix=new Matrix();
matrix.postTranslate(-200,-200);
matrix.postRotate(angle);
matrix.postTranslate(-200,-200);
化简公式为M`=T*R*-T*
混合使用前乘和后乘
Matrix matrix = new Matrix();
// 各种操作,旋转,缩放,错切等,可以执行多次。
matrix.postTranslate(pivotX,pivotY);
matrix.preTranslate(-pivotX, -pivotY);
M' = TM ... -T = T ... *-T
这种方法是为了避免两次平移被拉得太开,代码量多的话,会容易漏写。
pre 和 post 就是用来调整乘法顺序的,由于矩阵乘法不满足交换律,所以前乘后乘的结果是不一样的。
上面都是矩阵的基础知识的理解,到底该怎么用。下边开始总结:
Matrix的基本使用
先看一下Matrix的基础方法
方法 | 解释 |
---|---|
Matrix (); | 构造方法,创建一个新的矩阵,为单位矩阵 |
Matrix (Matrix src); | 构造方法,对src矩阵进行深拷贝,也就是创建一个跟src矩阵一毛一样的矩阵。 |
equals | 比较两个Matrix的数值是否相同。 |
hashCode | 获取Matrix的哈希值。 |
toString | 将Matrix转换为字符串: Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} |
toShortString | 将Matrix转换为短字符串: [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0] |
void set (Matrix src) | 没有返回值,有一个参数,作用是将参数Matrix的数值复制到当前Matrix中。如果参数为空,则重置当前Matrix,相当于reset()。 |
void reset () | 重置当前Matrix(将当前Matrix重置为单位矩阵)。 |
void setValues (float[] values) | setValues的参数是浮点型的一维数组,长度需要大于9,拷贝数组中的前9位数值赋值给当前Matrix。 |
void getValues (float[] values) | 很显然,getValues和setValues是一对方法,参数也是浮点型的一维数组,长度需要大于9,将Matrix中的数值拷贝进参数的前9位中。 |
数值计算方法
方法 | 解释 |
---|---|
void mapPoints (float[] pts) | 计算一组点基于当前Matrix变换后的位置,讲计算后的矩阵数值存放到pts数组中 |
void mapPoints (float[] dst, float[] src) | 与上个方法作用一样,只不过是讲计算后的结果存放到dst数组中,src不变 |
void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount) | 作用和上边两个方法一致,只不过可以指定存储的数组长度。dstIndex表示目标数据存储位置起始下标,srcIndex表示原数据存储起始下标,pointCount表示计算的点个数 |
float mapRadius (float radius) | 测量半径,由于圆可能会因为画布变换变成椭圆,所以此处测量的是平均半径。radius表示原半径,返回的是经过变换之后的半径。 |
boolean mapRect (RectF rect) | 测量rect并将测量结果放入rect中,返回值是判断矩形经过变换后是否仍为矩形 |
boolean mapRect (RectF dst, RectF src) | 测量src并将测量结果放入dst中,返回值是判断矩形经过变换后是否仍为矩形 |
mapVectors | 和上边mapPoints方法类似,不过这里测量的是向量,也就是说平移操作不会影响结果 |
set/pre/post控制平移(translate)、缩放(scale)、旋转(rotate)、 错切(skew) 的变换
上边在讲Matrix原理的时候就已经对这些方法进行过讲解。
特殊方法
setPoluToPoly()
boolean setPolyToPoly (
float[] src, // 原始数组 src [x,y],存储内容为一组点
int srcIndex, // 原始数组开始位置
float[] dst, // 目标数组 dst [x,y],存储内容为一组点
int dstIndex, // 目标数组开始位置
int pointCount) // 测控点的数量 取值范围是: 0到4
这个方法是控制两部分进行变换的。一是进行变换的点的数据,而是变化的点数。
srcIndex定义要变换哪些点,中心点可以,四边形四边中点可以,四边形四个角可以,这里去的是容易获取的点;dstIndex表示根据srcIndex变换后的点;pointCount是变换点的数量;比如说你上边定义了四个点的变化,但是pointCount是1,那么结果可能就不是你想要得到的。
pointCount | 摘要 |
---|---|
0 | 相当于reset |
1 | 相当于translate |
2 | 可以进行 缩放、旋转、平移 变换 |
3 | 可以进行 缩放、旋转、平移、错切 变换 |
4 | 可以进行 缩放、旋转、平移、错切以及任何形变 |
这个方法还是很有必要仔细研究的,具体代码我就不贴了,原博客中有详细讲解
setRectToRect
这个方法的作用主要就是填充的模式,比如一张图片要放到父空间中,图片尺寸比较小,那这张图片是要放在左上角,还是右下角,还是中间,还是铺满呢?setRectToRect方法就是控制这些操作的。
boolean setRectToRect (RectF src, // 源区域
RectF dst, // 目标区域
Matrix.ScaleToFit stf) // 缩放适配模式
模式 | 摘要 |
---|---|
CENTER | 居中,对src等比例缩放,将其居中放置在dst中。 |
START | 顶部,对src等比例缩放,将其放置在dst的左上角。 |
END | 底部,对src等比例缩放,将其放置在dst的右下角。 |
FILL | 充满,拉伸src的宽和高,使其完全填充满dst。 |
rectStaysRect
判断举行变换之后是否还是矩形。
invert
获取矩阵的逆矩阵
boolean invert (Matrix inverse)