- Android自定义控件高级进阶与精彩实例
- 启舰
- 7171字
- 2021-03-04 18:45:24
2.2 Matrix类中函数用法详解(一)
在本节中,我们将详细讲解位置矩阵Matrix类具有的各个函数及其用法。
注意:如果在使用Matrix类的函数时,发现效果与预期不同,请关闭硬件加速后重试。
2.2.1 基本函数
2.2.1.1 构造函数
Matrix类的构造函数有如下两个:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_20.jpg?sign=1739376233-X7jPHQy6uTbBpB94xGF08KU123vcouCo-0-6136f94afbe559f3722c5bb31a114351)
第一个构造函数经常使用,用于直接创建一个单位矩阵:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_21.jpg?sign=1739376233-CjE8d39wqbZhDKFBi4fDCN9oI3iFcLiT-0-d6f68859f1fb963c468c8974bafac4c6)
第二个构造函数则会利用一个已有的Matrix对象,复制出一个新的Matrix对象,其内部数据内容与已有的Matrix对象完全相同。
2.2.1.2 reset
reset函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_22.jpg?sign=1739376233-b8PGGsh5TaYAihVWgTykBb4KYw6YCqcv-0-4a2dab118e647d71efda65ff0929c04c)
该函数用于重置矩阵,重置的矩阵为单位矩阵。
2.2.1.3 setTranslate
setTranslate函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_23.jpg?sign=1739376233-XwFx7gBs214gRKGsxo1sWttXUin1yvoU-0-e82c7a8fc0c86ef0e8fd2097cf701e91)
该函数用于设置X轴和Y轴的移动距离。很明显,在Matrix中没有三维空间的概念,只有针对X轴和Y轴的操作方法,没有针对Z轴的操作方法。所以,Matrix对应的是2D坐标系。
●dx:X轴上的平移量。
●dy:Y轴上的平移量。特别需要注意的是,Matrix使用的是2D坐标系,在第1章中,我们讲解2D坐标系和3D坐标系时就提到过2D坐标系与3D坐标系的明显区别是,Y轴的方向是完全相反的。下面将通过实例来证实。
下面对第1章中的示例进行改造,不再使用Camera来操作图像,而是直接使用Matrix的setTranslate函数来实现平移,代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_24.jpg?sign=1739376233-6px5rkio4Y4DESImDxpjXBMRB5FHo3ea-0-3b57f22b8c4c1d04ed737bdc653b65df)
效果如图2-1所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_25.jpg?sign=1739376233-5VVylwzseeXU5fgJlsZBoz9ry5d0nsEB-0-bcc71d0469e6b3bbf5a79178fda797f1)
图2-1
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_26.jpg?sign=1739376233-celkHgr2TYDgGF8uYO87iq5CKPS4dGbs-0-0c06bac99010dadb3f9d1da8b44fe763)
扫码查看动态效果图
修改代码,改为沿Y轴平移:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_27.jpg?sign=1739376233-Of42gmWYMKA08ngT5KgtV5b4wXtepvGT-0-90a171da00c182a67ed00352a0da3b5a)
效果如图2-2所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_28.jpg?sign=1739376233-8sjUqdmOW8gVlOM16Vh060DYBKnDwBzJ-0-03cc75ad2f877ef504bf96811051bffb)
图2-2
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_29.jpg?sign=1739376233-KCHcFYfQHRxmmYYFbryfrLIeEkBoTwdT-0-4aca1f031102b8ef35e6808cbf2c8e9f)
扫码查看动态效果图
我们回顾一下在使用Camera实现Y轴平移时的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_30.jpg?sign=1739376233-EA5ASHLyiadL8KFbcUtbma8CmG3WxA76-0-75f23e9bd30037c1af48db3d2bf4b120)
对应的效果如图2-3所示。
很明显,通过Camera和Matrix实现的沿Y轴平移的效果完全相反。下面来看看2D坐标系和3D坐标系的区别,如图2-4所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_31.jpg?sign=1739376233-Zv7oOl2rkpJhjBDEognEb8hkQ7lhiKvB-0-104b439261bdd8b1b007a045e98868e9)
图2-3
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_32.jpg?sign=1739376233-xHutWZPedbttpAjYMmIp5ciHEmSkJcvx-0-aefb01595e7573e6034e1b9e046717bb)
扫码查看动态效果图
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_33.jpg?sign=1739376233-7yrVRKHNJWSt5ARFF0LJGMyVdW5S2RdU-0-7aaeea2dcec0bb365e96b590ca3d7e29)
图2-4
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_34.jpg?sign=1739376233-PsaIPTdvpjkeRxRHIev5lJv7CbU1kBEk-0-ccd4f87380f2e102d56c37a468a27eb3)
扫码查看彩色图
很明显,Matrix是基于2D坐标系来进行位置变换的,而Camera是基于3D坐标系的。但经过Camera操作后展现的效果,最终还是通过Matrix来实现的。如果我们直接使用Matrix来操作控件位置变换操作,那么它使用的是2D坐标系。关于这一点,大家一定要分清。
2.2.1.4 setRotate
setRotate函数的声明有如下两种形式:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_35.jpg?sign=1739376233-KXMuiIVqv1dRKpJx1l7Vrfmsltyvw5PX-0-05ce8632d474cf1b260853722f081165)
该函数主要用于设置旋转角度,参数具体含义如下。
●float degrees:旋转角度。
●float px:旋转中心点的X坐标。
●float py:旋转中心点的Y坐标。
在第2个声明形式中是没有旋转中心点的,默认会围绕控件左上角原点进行旋转,比如下面的示例代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_36.jpg?sign=1739376233-luisXVySxrzS7OCNbipZO7bpUICcxQ2j-0-0dcc688bd70ae0f06ad1677ad754a621)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_37.jpg?sign=1739376233-nmt6lAkqr9xsiusT7hMVgMRGKs8vrcc0-0-4776d85c2e95b386dbeab7c4ff34dfc1)
效果如图2-5所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_38.jpg?sign=1739376233-eGQvHFwSYIACXqF2Af4XI3zsU0AqHsR3-0-b4900ec6350dfb7e5acb15d7c91f820a)
图2-5
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_39.jpg?sign=1739376233-H8xCMyESUmhqRySMFgCy4Fa8p11TBSMV-0-645942ca77637225aae5bc040f1f8f34)
扫码查看动态效果图
可见,使用matrix.setRotate(mProgress)实现的旋转操作,是以左上角为原点来进行旋转的。
假如,我们将旋转代码进行变换,以(50,50)为旋转中心点:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_40.jpg?sign=1739376233-ntcG7DqyuSojoH6eyUM2w23UzytVQ6yc-0-592cfade0ce80f3749402aea743ff986)
效果如图2-6所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_41.jpg?sign=1739376233-jw5Ay8PP0qsP9Wm6HnsX4mjjq8Cc9fqk-0-0eeb461419b12e1b126e9be7a6c48540)
图2-6
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_42.jpg?sign=1739376233-2XoW8qtAPioXTamV1nHHrW3GJX8MkByC-0-88cffef8d70ea8e1bcc32a52b2932fa4)
扫码查看动态效果图
2.2.1.5 其他set相关函数
在Matrix中,还有其他set相关函数,由于理解难度较大,这里先不提及,后面还会讲解。
2.2.2 前乘与后乘
在Matrix中,除了set系列的函数,还有pre、post系列的函数。
平移相关的函数有:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_43.jpg?sign=1739376233-2AA5UZ4yRn76YSAbR6XaPz204wk3CeMv-0-0a93c379b9015bef821eef0d8c18106d)
旋转相关的函数有:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_44.jpg?sign=1739376233-JN31rCCO434P2ngIGH5Pi1JRsftOi88f-0-3ea3a4bd8ce9c9c23232228e47d1219b)
另外,还有其他操作方法,虽然此处没有提及,但凡是set系列函数中有的功能,都有对应的pre、post系列函数。
2.2.2.1 前乘与后乘的定义
既然每个功能都有pre、post相关函数,那什么是pre、post呢?
前乘:
前乘相当于矩阵的右乘,如下方公式所示:
M'=MS
M表示原矩阵,S表示另一个乘数矩阵,M'表示结果矩阵。
很明显,前乘表示原矩阵在乘号的前面。
后乘:
后乘相当于矩阵的左乘,用很容易理解的方式来看,就是原矩阵在乘号的后面:
M'=SM
同样地,M表示原矩阵,S表示另一个乘数矩阵,M'表示结果矩阵。
Pre与Post
以在原矩阵上使用matrix.preTranslate(10,15)为例,那么矩阵的乘法次序如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_45.jpg?sign=1739376233-WoypGw1BMZyxO06dTLh5d4wKQw7S5zed-0-8076ebb1a037ba72926ab8f4363ac28f)
在上面的公式中,Translate操作对应的矩阵的缩写为T,很明显,前乘的操作方式是原矩阵在乘号前面。
同样地,如果我们在原矩阵上使用matrix.postTranslate(10,15),那么矩阵的乘法次序如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_46.jpg?sign=1739376233-dKW8r87tHNuuD6sUNbbfbOHtqYLpjmnh-0-e4a72ddcf330308f0695b19c01ea2679)
很明显,原矩阵在乘号的后面。
区分前乘和后乘的主要原因是,矩阵乘法不满足交换率。
再增加一点难度,如下面的伪代码,其中同时运用了多个pre和post运算,这时的运算顺序是什么样的呢?
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_47.jpg?sign=1739376233-oxFzSUavCXQxnD0adaenQwjc12nMhnVg-0-803eeda949ba7ca642b78e7d81a6ea87)
假设Translate操作对应的矩阵为T,同样地,Rotate操作对应的矩阵为R。
下面逐步分析这段代码对应的矩阵操作顺序。首先是第1步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_48.jpg?sign=1739376233-0huv4vNU9gKfkjHgo0y1Vnry8xamNkYF-0-159e1be44b2efe7745537f90b0906f51)
这一步创建了一个单位矩阵,假设该矩阵为M,此时的结果=M,其中
表示该步的结果矩阵。
然后是第2步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_51.jpg?sign=1739376233-yXNcuOHfdOD711fyyXzgF0ShiBsi6TU4-0-84927cc7db5cc8d20add1c5688cebb90)
在原结果矩阵上前乘一个Translate操作,假设该Translate操作对应的矩阵为T1,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_52.jpg?sign=1739376233-rvaGeq7XHQJo9NGi0MHjvi9YbfC7uNni-0-3283c10ef14ba1cd01f62f53013a981c)
其中是第2步代码执行完成后的结果矩阵。很明显,它等于当前的结果矩阵
前乘T1矩阵。
接着是第3步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_55.jpg?sign=1739376233-g8pNberjcloWBMoqBFk6ZDOxgmSkylLX-0-fcb05c83eb98412f55df18e5af421ffd)
同样地,是在当前的结果矩阵的基础上前乘Rotate操作,假设该Rotate操作对应的矩阵是R,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_57.jpg?sign=1739376233-vjvWTEjiJjfGpZhve9zuKL2QqHspHm2K-0-e96707fd5b4fa2185f354402bcc0be13)
是第3步代码执行完成后的结果矩阵。
最后是第4步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_59.jpg?sign=1739376233-OdY4nHuRGL1J1wSNlDgyoOLwPYtgDLU7-0-3914e6df48b10cab5fbaea4c4ec19bbf)
表示在当前结果矩阵的基础上后乘一个Translate操作,假设该Translate操作对应的矩阵是T2,那么整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_61.jpg?sign=1739376233-gEiRnyu2Xlp5k78CuTFtCWP3qvJJbVBK-0-701b0536b82270e9957205e295bed0f3)
是第4步代码执行后的结果矩阵。可知,
是整段代码执行后得到的最终矩阵。
上述换算过程演示了矩阵的前后乘关系,以及如何通过公式表示整个过程,这个过程在后期代码中非常重要,很多时候,我们需要知道如何将想法转换成公式,最终通过代码将公式写出来。
2.2.2.2 更改旋转中心点
在第1章中,我们经常会在所有操作结束之后,将操作的中心点移到图像的中心点,即通过如下代码来实现,下面就来讲解代码的实现原理:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_64.jpg?sign=1739376233-O67rFDanTJ5fMGSaqvSjiA11EF1cojrb-0-07755426d386ad0be4b724c80230f350)
首先,针对各种操作,有两条基本定理需要知晓。
(1)所有的操作(旋转、平移、缩放、错切等)默认都是以坐标系原点为基准点的。
(2)之前操作的坐标系状态会保留,并且影响后续的状态。
第1点可以根据第1章Camera的操作效果及前面的Matrix的操作效果可知。第2点是很明显的,我们每一步操作都基于前面所有操作的结果矩阵,这一点已经在2.2.2.1节讲过了。
基于这两条基本定理,可以推算出要基于某一点进行旋转需要如下步骤(所有操作中调整中心点的原理都是一样的,下面以旋转操作为例)。
●先将坐标系原点移到指定位置,使用平移矩阵T。
●对坐标系进行旋转,使用旋转矩阵R(围绕原点旋转)。
●再将坐标系平移回原来的位置,使用平移矩阵-T。
从上面调整旋转中心点的过程可以看出,其实是先将坐标系的原点平移到指定位置,然后在这个位置上完成操作以后,再把坐标系的原点移回去。
因为我们在第2步中执行各个操作时,原点的位置已经改变,所以操作后得到的就是我们想要的图像状态。最后,将坐标系原点位置移回去,这是为了不改变原来的坐标系位置。
在第1章中,我们已经讲解过,在调整坐标系原点后,图像的显示位置就会发生变化,大家可以自行尝试。
根据上面的步骤,将其转换成矩阵相乘的公式,即下面的公式:
M'=M×T×R-T=T×R-T
其中:M为原始矩阵,是一个单位矩阵,M'为结果矩阵,T为平移操作矩阵,R为旋转操作矩阵,-T反向平移操作(即把坐标系原点移回的操作)矩阵。
如果按照公式将其写成伪代码,代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_65.jpg?sign=1739376233-pIJ0y90QQ02cC3i826giXvnEi24aQoeC-0-3448ca0166e440d3380e4aea1c01230d)
所以,如果对该代码进行扩展,改为任何操作改变坐标系原点的通用情况的话,矩阵乘法公式变为:
M'=M×T××-T=T××-T
其原理也很简单,先通过平移操作将原点位置移到指定位置,然后对图像进行各种操作,操作完成后,再把原点位置移回去。
相应的代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_66.jpg?sign=1739376233-6VQOTMpro4Oob11z7zBFc2o0ULDvPpKh-0-e1418ae9e80d3d9d9a377ba79d95a8ad)
上面的代码逻辑非常简单,就是从前往后,每执行一个操作都使用一个pre函数,这样写虽然逻辑简单,但两个调整坐标系原点的平移函数——preTranslate函数,一个在整个代码段的最前面,一个却在整个代码段的最后面,就公式而言不好记忆,所以通常采用这种写法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_67.jpg?sign=1739376233-YX8wzVLTmI2DJMbbUNNsA4ks1BbbXXXz-0-7677a48e36045ce16fd89c13309d48d9)
即先做各种操作,然后使用preTranslate函数和postTranslate函数来操作。
这段代码所对应的公式如下:
M'=T×M ××-T=T××-T
因为M是单位矩阵,所以最终化简结果与上面采用两个preTanslate函数的结果是相同的。这完全利用了前乘与后乘的功能。
因此,pre和post相关函数就是用于调整乘法顺序的,正常情况下应当以正向顺序构建出乘法公式,之后根据实际情况调整。
一般情况下,我们在确定矩阵公式以后,仅使用一种乘法(前乘或后乘)形式,这样的代码更容易理解,出问题时也容易排查。如果混用前乘和后乘,则会造成混乱,理解难度加大。但大家只需要理解了上述转换过程,无论别人如何混用前乘和后乘,对你来说都不是问题。
2.2.3 其他功能函数之缩放(Scale)
在理解了前乘和后乘的意义之后,我们继续讲解2.2.1节中没有讲解完的功能函数。
缩放功能涉及的函数有:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_68.jpg?sign=1739376233-pssC7xQA3oP1cLOJwSGsY6dGXnQe4to5-0-6d3a7a22b3de6142d90f9a46c0e1f8b7)
可以看到,函数名中除了有set、pre、post前缀的区别外,主要有两种声明方式,下面以set系列函数为例进行说明。
●float sx:代表X轴上的缩放比例,取值范围为(-∞,+∞),其中+∞表示正向无穷大,-∞表示负向无穷大,所以(-∞,+∞)的意思是可以取数值区间里的任意值。
●float sy:代表Y轴上的缩放比例,取值范围仍为(-∞,+∞)。
●float px:代表缩放中心点的X坐标值。
●float py:代表缩放中心点的Y坐标值。
其中sx和sy最好理解,就是指常规的缩放比例。当缩放比例在-1<sx<1时,缩放效果是缩小;当缩放比例在sx>1或者sx<-1时,缩放效果是放大。另外,缩放比例还有正值和负值的区别,缩放比例取负值时表示根据中心轴进行翻转。
px和py比较难理解,它们表示缩放中心点的坐标值,在默认的情况下,缩放中心点位于图像左上角。而(px,py)表示的缩放中心点是什么意思呢?在缩放时,又是如何根据缩放中心点来进行缩放的呢?我们稍后一并分析。
2.2.3.1 Scale函数的具体作用
在本节中,我们来看看sx与sy取不同值时的效果。
为了方便理解,我们以一个demo为例,新建一个自定义类View,继承自类View,其专门用于测试Scale函数的相关参数,该类被命名为testScaleView,其实现如下面的代码所示。关于onDraw中的具体内容,我们会放在后面具体讲解。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_69.jpg?sign=1739376233-BI2MandIpv2JtwcvzxrSbMe54u5OqrnM-0-0d6999488a9a465c3d548adf4dfe152c)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_70.jpg?sign=1739376233-vLedEMsIor978h6IwtFVZfrGdzBPuwTA-0-68b17799a4737f250aa53038a2a40aee)
在使用testScaleView时(activity_test_scale.xml)进行全屏展示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_71.jpg?sign=1739376233-RbsFSw9FiCHw4vy6Oq0KRcBwKSCDdo4t-0-f1f90d76b883c0f6bc065622918f6183)
效果如图2-7所示。
根据如图2-7所示的效果图,我们来重新看看在onDraw中具体执行了哪些操作。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_72.jpg?sign=1739376233-T0HFxYX6mGXUZgY4UmzjqndWWNQrZrTh-0-38608ba7672ea617685f7992b35fedbf)
图2-7
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_73.jpg?sign=1739376233-zboGwwWksJjGtquE6zWhwQjqfiasBNPU-0-6d6780b996e34d68d893cc0ac5c1b270)
扫码查看彩色图
1.移动坐标系原点位置
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_74.jpg?sign=1739376233-JroxHz0F3oeJcoqTEPeokMnKHlLxGqtP-0-3cc50f3200bec072bab60b7b1cf18f9c)
因为testScaleView是全屏显示的,默认的坐标系原点位于View的左上角。为了方便理解,先将View的坐标系原点移到整个View的中心点位置。
2.绘制矩形
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_75.jpg?sign=1739376233-63NNIC1yrJKlPSKy1V4WB3XjWO1KUti8-0-55a4f6aeb0b863fc74bb6fedcf97c17d)
根据最新的坐标系位置,绘制出矩形区域,如图2-8所示,图中标上了坐标系,方便读者理解。
此时画出来的是RectF(0,400,400,0)这个矩形,即黑色方框。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_76.jpg?sign=1739376233-vSySyVm2WDonOfCGstX48nBiyjaDafkt-0-e448f06abfcecec8997d2bb77068371e)
图2-8
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_77.jpg?sign=1739376233-AyWfLIPm0dHoIWOtQEcDuboebUeUbDQN-0-cb5244eb0fcaebf8d2c638f9504c89c5)
扫码查看彩色图
3.缩小标尺
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_78.jpg?sign=1739376233-DyEEMUc4BHyrH89L8RcgGUnXmbdSqKmp-0-01c1c374b8cae824f2ac3024a6df5ba2)
需要注意的是,matrix中的所有操作都是针对坐标系的,比如上面的translate函数,在操作后,改变的是坐标系的原点位置。同样地,scale操作同样针对的是坐标系上坐标轴的密度。需要注意,我们可以分别针对X轴和Y轴缩放标尺密度。
比如,这里的preScale(0.5f,0.5f)就是将坐标系X轴的标尺密度缩小为原来的50%,即原来10像素的宽度现在变为5像素的宽度,但它表示的仍是10个像素,变换过程如图2-9所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_79.jpg?sign=1739376233-ZoB99D3aIjcgecB3upBbfpVTuwynDVAL-0-7f878a22a8fd28c4806754160802b59b)
图2-9
图2-9表示在标尺密度缩小为原来的50%后,表示同样的数值仅需要原来一半的标尺宽度,这就是Scale函数的作用。
4.重画矩形
在缩小了标尺密度以后,我们重画RectF(0,400,400,0)矩形:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_80.jpg?sign=1739376233-tMjSTsBdLvPuTfvrviUK7V5xbi2gXAwJ-0-c6b78340d87f425e8ec586d0b07ca4d3)
此时,所画的矩形就是在缩小密度后的标尺上绘制的,绘制的矩形就是效果图中的红色矩形框。
2.2.3.2 sx与sy的取值
上面已经提到,sx与sy的取值范围为(-∞,+∞)。当缩放比例在-1<sx<1时,效果是缩小;当缩放比例在sx>1或者sx<-1时,效果是放大。另外,还有正值和负值的区别,取负值时表示以中心轴进行翻转。
在前面,我们已经讲过sx和sy同时取0.5时的效果,而取值大于1时会出现放大的效果,这里就不再演示了。
下面着重演示一下,取负值时的效果。
我们将代码改为:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_81.jpg?sign=1739376233-UxCLAwdrmbd8haGSF2qgyKJKTPFTRtfM-0-9eeba4c7c4c44950b690bb1bbaa8e91e)
这里其实只改了一句代码:matrix.preScale(-0.5f,0.5f);,它的意思是不仅将X轴和Y轴的标尺密度同时缩小为原来的50%,还将X轴的方向进行翻转,原理如图2-10所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_82.jpg?sign=1739376233-cO6U5cEDLyLL5JQhIJPUJnVHucPmDZV6-0-5af3e34f0d0e2dc91a45ca6ce2e044f8)
图2-10
左图表示正常情况下的X轴与Y轴的正方向,右图表示X轴翻转后的X轴和Y轴的正方向。
在这种情况下的效果如图2-11所示。
效果图不难理解,黑框位置没变,红框在X轴上进行了翻转,这就是取负值时的效果。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_83.jpg?sign=1739376233-ccYMJwub8IMOxcp5wt2a5TjWO5GV05iH-0-54a4891216fd16898a054d0fc8d06393)
图2-11
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_84.jpg?sign=1739376233-gqJzpV518YhXQUIU4KAsbaH41T9R0EXX-0-ec29b12c7e48cc58edc73d904614b589)
扫码查看彩色图
2.2.3.3 缩放中心点的作用
从各个函数的声明可以看到,除了sx、sy外,还有px、py两个值,比如:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_85.jpg?sign=1739376233-oUNV8thmTesWfu9YYyhu9a3TsavE9xwT-0-7601c41811b437d1e17fb1a5dcf4ae1f)
从前面的内容可以知道,px、py表示缩放中心点的坐标值,但缩放中心点是什么意思呢?
因为Matrix的源码在Android中是用C语言实现的,但Matrix的具体实现与Canvas中操作位置的函数相对应,Canvas中也有缩放函数,它们最终也是通过Matrix来实现的,Canvas中的scale函数声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_86.jpg?sign=1739376233-GUS8pTUMrsiEKCeryFZqFzEreOkyVOMe-0-b425b3948ee3cd3e3b56f735e2b24e63)
如果深入Canvas的scale函数的源码中,就可以看到它的具体实现:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_87.jpg?sign=1739376233-kgT1a37rpICj662UiZ6E4cWKPabfWbgZ-0-4209bfa226a6bfddf85c012c52ab927c)
其实这就是Matrix的带有缩放中心点的Scale函数的具体实现,分为如下3步。
●第1步:将坐标系移动到由px、py指定的位置。
●第2步:根据sx、sy的值缩放坐标系。
●第3步:反向移动(px,py)距离。
这里有一个陷阱需要注意。第1步和第3步是完全相反的操作,有些读者一马虎,会把坐标系原点移回原来的原点处。大家千万不要忘了还执行过第2步,第2步将坐标系进行了缩放,而这会导致在第3步中虽然移动了同样多的像素点,但所对应的坐标值根本不一样。参考上面红框与黑框的关系,这一点很容易理解。
下面,我们举一个例子:同样是上面的缩放例子,但此时,在X轴/Y轴的标尺密度同时缩小为原来的50%时,选定一个缩放中心点(400,400),代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_88.jpg?sign=1739376233-BdgwyHD1ZRzphKWRYtTq2oE4QAgsfZ39-0-4ce070be99f1ff3e79637fabbc809887)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_89.jpg?sign=1739376233-Qg3Kf2JyQg248ScxsRCxlNLm7AVQ3VJ3-0-b2a6e79571a14040fdb7a302fad7ad7a)
此时的效果图如图2-12所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_90.jpg?sign=1739376233-iC4ZgaPezGFXPBfeMMu2GdLgqaUigfz8-0-a22e56b4220168d67e667e82e1e89c96)
图2-12
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_91.jpg?sign=1739376233-X05zLEhIDZicLBYxBgtY3Uv7PbKkKeDE-0-a8d413e445edb0cf7f0c078fa52e0b53)
扫码查看彩色图
它的完整变换过程如图2-13所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_92.jpg?sign=1739376233-O4ttpqUNquwbH3maQd6DhQQYItRJn3aQ-0-c2f662d323f0dce308d639688bd532b1)
图2-13
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_93.jpg?sign=1739376233-LyQ0REfRBdLH04WDCoSQAC2ihumSGtZM-0-727054a4ceea98679589409e1f326992)
扫码查看彩色图
从图2-13可以清晰地看出,matrix.preScale(0.5f,0.5f,400,400)函数所对应的3步变换过程。需要注意的是,变换开始时,坐标系原点在黑框左上角,而当变换结束时,坐标系原点已经变到了黑框中心点位置。因此,这一点需要特别注意,在使用缩放功能中带有缩放中心点的函数时,会改变坐标系原点的位置。具体使用后,原点位置在哪呢?可以在所有操作结束后,利用canvas.drawCircle(0,0,5,mPaint)函数,在坐标系原点位置画个圈。比如,我们在Scale操作结束后,利用该函数来画个圈,相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_94.jpg?sign=1739376233-1Qz8dDVaEL8wqcDNNN198mgvEahncTKV-0-8918520b2f688ded9ff1b7ca1230cf87)
效果如图2-14所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_95.jpg?sign=1739376233-rVzyJN1Nzz8KzNUE041wpU1UsqZwwsVC-0-dddef1feaf754e48fdf3a920b403c970)
图2-14
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_96.jpg?sign=1739376233-DLH8AiF2BouAgom4gg1kpbvooQaNyGKY-0-8f00c7fa01b9d7a2efae022d4645a916)
扫码查看彩色图
2.2.4 其他功能函数之错切(Skew)
2.2.4.1 错切的意义
在正常情况下,坐标系中的X轴与Y轴是相互垂直的,而错切的意思就是让某个轴倾斜。
X轴错切(如图2-15所示):
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_97.jpg?sign=1739376233-PV3r6XtYG5W5SdqT0X395CGMqk80bX5B-0-0e97456ad8af7a34b30cefdb78896e97)
图2-15
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_98.jpg?sign=1739376233-QPfWS8xNUzNlHuZ9du2r2xwlS1cR4G6s-0-60784336c044b2d831f60a6cc01f6f3e)
扫码查看彩色图
X轴错切时,是保持坐标系的Y轴不变,X轴的值做线性变换,表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_99.jpg?sign=1739376233-EOa75E2Q4uQt6m22Qe5tDR6gxnAY2Gki-0-517722c29e5abf82eef907aadf3d5d2e)
可以看出,对应到每一个点上,y坐标都没变,而x坐标都向后推了ky0的距离。所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_100.jpg?sign=1739376233-hoi2cXwlFtjFv8B0T5gYZISL8iw0EDfp-0-a1a657a64692048d0c79b481573d9979)
注意变量k所在的位置,前面我们讲解位置矩阵的各个标志位时,已经提过该位置的含义,其主要用于标识SKEW_X:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_101.jpg?sign=1739376233-gdDnnfz11MwrfdwuoYSexjWBuDqFcRII-0-f29adf816f4730d14e0c8567598b8770)
需要非常注意的是,在X轴上移动ky0距离后,倾斜的是Y轴方向,X轴方向上没有变化,从图2-15可以清晰地看出,斜率k表示Y轴方向上的倾斜程度。也就是说,在X轴错切后,改变的是Y轴方向上的斜率。
Y轴错切(如图2-16所示):
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_102.jpg?sign=1739376233-XWErgaxAeeNu42v25vQCVXWKyq7PpuKZ-0-9aa9337821829cf08a0295706e5786b3)
图2-16
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_103.jpg?sign=1739376233-FZQBZsxKUXIwDzCaAGXYpA53rOPnLCqr-0-f7a9d17a19b0e50949fc306856494340)
扫码查看彩色图
同样地,所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_104.jpg?sign=1739376233-4KIEJQVqjCw0XJt01PxvkOdX8yWz3Hp3-0-58cbcc2376a757e9a7e9469a01f56789)
同理,在Y轴错切时,改变的是X轴方向上的斜率。
X轴、Y轴同时错切(如图2-17所示):
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_105.jpg?sign=1739376233-pCGmT2juR3kIdynru2deZxqg9fb4PKjF-0-32104626f543f269a26595156508dce6)
图2-17
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_106.jpg?sign=1739376233-OqD3jxJEIFbYEjlCGZmApz8gcpuZqHyp-0-8463d25a44d7e32a0bbc4e0bb2507387)
扫码查看彩色图
在X轴、Y轴同时错切时,表示在X轴和Y轴方向上同时倾斜一个角度,很明显,两个倾斜角度是完全独立、各不相关的。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_107.jpg?sign=1739376233-aNzT3NpxEQXSuryYNjpeJedGQeTeIoXa-0-5e7b4bb9bc50c1914e830b01da2ec291)
m表示X轴方向上的错切值,n表示Y轴方向上的错切值。
2.2.4.2 错切的用法
在了解了公式之后,下面来看看Matrix中Skew相关函数的声明及使用方法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_108.jpg?sign=1739376233-iaxJOaGe0KILzYuH6kpSRjrTVjMnb3oF-0-fcb7cd0cdf7a003947b30fa2f6177b61)
同样地,除了set、pre、post前缀的区别外,其实只有两种声明方式且涉及4个参数。
●float kx:将原坐标点在X轴方向上移动一定的距离,即在Y轴方向上倾斜一定的角度,kx的值是倾斜角度的正切值。
●float ky:同样地,将原坐标点在Y轴方向上移动一定的距离,即在X轴方向上倾斜一定的角度,ky的值是倾斜角度的正切值。
●float px:与Scale相关函数的参数一样,表示错切的中心点位置的x坐标值。
●float py:与Scale相关函数的参数一样,表示错切的中心点位置的y坐标值。
与Scale相关函数指定缩放中心点的意义相同,setSkew(float kx,float ky,float px,float py)所对应的操作如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_109.jpg?sign=1739376233-MnlVkR5oMVFzpom6ICdwQOh0or5FOLVu-0-13a6db69ee4e7cf42b7eb3390dad910c)
同样需要注意的是,虽然第1步和第3步看起来是完全相反的平移,但因为第2步的错切操作改变了X轴和Y轴方向上的倾斜角度,所以在经过第3步后,会改变坐标系原点的位置。
下面对代码进行整改,将上例中的错切操作改为matrix.preSkew(1,0),即在Y轴方向上倾斜45°:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_110.jpg?sign=1739376233-cFUkkDhIzztVmk7mwytIdPZTkGQ1c1hd-0-360e17cc1b500f4ff2f62b4431b19170)
效果如图2-18所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_111.jpg?sign=1739376233-5ktlQuel3fR6lR7NRn66n5IeyGVVg2SH-0-7f779cbfbd77e4fc53b6ab64dfe55bc8)
图2-18
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_112.jpg?sign=1739376233-zbWaEPpGjBDr64VJhHJKQ3glYCaqOOTP-0-61c300897016749b2d69cd4b43029527)
扫码查看彩色图
可以看出,由于Matrix操作的是坐标轴,所以在Y轴方向上倾斜45°时,所画矩形已经不是正常的矩形了,这是因为Matrix改变的是坐标轴方向上的倾斜角度。
下面再尝试一下matrix.preSkew(1,0,200,200);:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_113.jpg?sign=1739376233-vHHkLyj7YsNt7ZDI3inmCD0Jj7hsD6Ol-0-782e94e95d55bf5af5a6731824bf3bf7)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_114.jpg?sign=1739376233-rqdzO4wS96mQBkKTJSP5MW45YpZQotbm-0-baf1a61563dc97a8058c801097bd2c09)
这里什么都没有改变,只是单纯地使用了Skew相关函数有错切中心点的声明方式,错切中心点为(200,200),效果如图2-19所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_115.jpg?sign=1739376233-ipcz5eBezEFxu73OW2sForbhNKOQ9CB6-0-0472da72be10adc398f025e089a21aee)
图2-19
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_116.jpg?sign=1739376233-iXo1CsD8PvyDqof8rVkQBIvpO7RLHeX0-0-25ccc4b0fb041aa3c4eb981077811f90)
扫码查看彩色图
乍一看可能有点困惑,图2-20展示了以上完整的实现过程。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_117.jpg?sign=1739376233-YgTMn8WLkGkQ0q61uQUyK2M0VM9U2TW5-0-85c5523ffa1c5525b9a6f9f35e45903f)
图2-20
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_118.jpg?sign=1739376233-vHsQtlBWQm4VspPrZNIPnXEMwbHO1Qc0-0-861f735efa03c9c16e94755e98a8a340)
扫码查看彩色图
在第4步中,回移至点(-200,-200)可能会让读者产生疑问,下面我将这一步进行分解,如图2-21所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_119.jpg?sign=1739376233-POPuaUzTpGBeSw4ZyPaDuJEoZUDhn7b8-0-24751dbca99bde877e05e3fb69a0c36f)
图2-21
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_120.jpg?sign=1739376233-vCAbF1mxsr2G2fgK9rW0rIEj5TPAdXzm-0-76c10e8f743de7dd448e95ac2ee1fde6)
扫码查看彩色图
2.2.5 其他功能函数之setSinCos
setSinCos函数主要用于旋转操作,但它的函数声明比较特殊,如下所示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_121.jpg?sign=1739376233-4do4281i9LAZOjdE3HnU0fSLgeTc0Lpt-0-5960bb146f65b6748fe57599d652b205)
●float sinValue:旋转角度的正弦值。
●float cosValue:旋转角度的余弦值。
●float px:旋转中心点的x坐标值。
●float py:旋转中心点的y坐标值。
关于旋转中心点(px,py)的意义,与上面介绍的各个中心点的意义是相同的,setSinCos(float sinValue,float cosValue,float px,float py)其实也执行的是下面3个步骤:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_122.jpg?sign=1739376233-a5ERFazv65DdW3hkdt65HkuMM1MG91hZ-0-9fc969c68ce53f8f3cdf6fc59ddcd951)
在这里,我们就不重复讲解了,大家可以实际操作一下,然后利用画图解析的方式来复现一下它的操作步骤。
2.2.5.1 setSinCos函数的意义
在调用public void setSinCos(float sinValue,float cosValue)后,所形成的矩阵如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_123.jpg?sign=1739376233-kXXZlMwCWm3GLcVREKvdqA4K5fMnmpZk-0-0b686fd4fcd363f2a227bda1f7aff789)
这个矩阵形成的原理如下:假设有一个点P,其相对坐标系原点顺时针旋转后的情形如图2-22所示,同时假定点P离坐标系原点的距离为r。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_124.jpg?sign=1739376233-q9zSw6wPBCmSeeGebCdoJqBKUuz0woz8-0-69eac3910252a8802ec863271d852728)
图2-22
假设在未旋转前,点P所在的位置为(x0,y0),而点P离坐标系原点的距离为r,所以用r计算出来的(x0,y0)如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_125.jpg?sign=1739376233-xrxX9rqy3qAvZ3t52tyI1q1E0zp4DClc-0-b45b8c07e002b2f4ebde3389437a9c33)
假设在点P旋转θ角度后,其新坐标用(x,y)表示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_126.jpg?sign=1739376233-WMtVhQuUJH0wKiNMcFCbmm33gEz596Px-0-f4f422b7a96c068a71d9894722613197)
转换为矩阵表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_127.jpg?sign=1739376233-rZZZhY1j5oaBGtye42KDa8HM4eJF82PB-0-4b2eaac8c9b85c2fbda0e5944da909b4)
所以,setSinCos函数只是一种旋转方式。一般情况下,不怎么使用这个函数,而使用Matrix的Rotate相关函数。
2.2.5.2 setSinCos函数的用法
下面演示一下setSinCos函数的用法,将示例代码改为:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_128.jpg?sign=1739376233-z4rgVAXCH3jalUAYSPIHjYE2cx8Zsy5y-0-c30c8103b2dceacff61f17751c3bbccb)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_129.jpg?sign=1739376233-RrHwrBUS94cCnzehgwJt1wWpTPGipLNl-0-74e6b908cac99f73cad84bc7882588a6)
代码长了好多,下面逐步进行讲解。首先,第1步画黑框部分的代码没有变化,这里就不赘述了。需要注意的是,为了进行区分,将构造的Rect实例改为了矩形。
在第2步中,我们并没有直接使用matrix.setSinCos函数,而是先生成了一个tmpMatrix,然后利用matrix.preConcat函数将旋转操作组合到原Matrix数组上,这是为什么呢?
因为Matrix的所有setXXX操作都会把原Matrix清空,然后执行所需的set操作。所以如果直接使用原来的matrix.setSinCos函数,就会发现Matrix原有的Translate操作都没有了。为了能让移动和旋转操作同时生效,需要使用Matrix组合数组的功能函数。我们在后面会讲到这些函数,也就是matrix.preConcat(tmpMatrix),它表示在原数组前乘tmpMatrix,所得到的结果必然同时具有移动和旋转效果。
在第3步中,代码也没有变化,都是在操作坐标系之后重画黑框,下面来看看操作坐标系后的效果,如图2-23所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_130.jpg?sign=1739376233-wC1umJAjOfDUTobi0skfJlaOoIY3usvQ-0-92f7e557c29fe09461044870c2946612)
图2-23
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_131.jpg?sign=1739376233-wO3CqAh8aYxJ3e59O5KKbiy4pwcVEWmo-0-06a0c62728fb3468c21e4dffebb6bf55)
扫码查看彩色图
到这里,大概了解了Matrix中一些函数的用法,但Matrix中的函数不止这些,后面我们将继续讲解Matrix中其他函数的用法。