![Android自定义控件高级进阶与精彩实例](https://wfqqreader-1252317822.image.myqcloud.com/cover/747/36511747/b_36511747.jpg)
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=1738870403-sMd30C0ppuwzZjlgeTphT9WjOeUyJkt1-0-c3dceb02522d0567e041a5386cb34b32)
第一个构造函数经常使用,用于直接创建一个单位矩阵:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_21.jpg?sign=1738870403-E5TpWnG7ftRo4P2G6wBe2X6aRjLu9x9y-0-90f848bdf67bf9d5d22319a5ec91ca22)
第二个构造函数则会利用一个已有的Matrix对象,复制出一个新的Matrix对象,其内部数据内容与已有的Matrix对象完全相同。
2.2.1.2 reset
reset函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_22.jpg?sign=1738870403-vC4tcDFYJcJePDC1EHYl0sx5j0fWPokJ-0-aa1d6087418afd54781189013c002274)
该函数用于重置矩阵,重置的矩阵为单位矩阵。
2.2.1.3 setTranslate
setTranslate函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_23.jpg?sign=1738870403-k9OKYfztQXwrijUDxKnoisvCTPAg6OzT-0-7c7e155941e8393edefde1faec9d95d7)
该函数用于设置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=1738870403-NJZRDruJNV8QiC1ztOYwiyELL4I6UehQ-0-556b484e6b05004070f83b90160418cf)
效果如图2-1所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_25.jpg?sign=1738870403-wU0pFhHzpWF9aF4iCdl1kvHO3SNvW8oM-0-d0b4273e2e8ce1b561c96c35a7229640)
图2-1
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_26.jpg?sign=1738870403-epM1lf9CcIOASotxAws3xgJ02Da8pUkP-0-56d28fb87f60a89e79a0477d3a2b64ce)
扫码查看动态效果图
修改代码,改为沿Y轴平移:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_27.jpg?sign=1738870403-UMr49ps8IfNbQYsSEmIecy1GcV83VZPc-0-3dab6fd163174c6a8b900d1580585cba)
效果如图2-2所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_28.jpg?sign=1738870403-mJ14v3vbpvTGjczlIkaXSyVKxSM7aYWk-0-039ae9a9719e42e3af58d1ddf4b29e02)
图2-2
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_29.jpg?sign=1738870403-QOMpaBs5FEbW9g7yFDkUH09bm3M218tD-0-011ffffa79ae6ef18d50728e5785d1de)
扫码查看动态效果图
我们回顾一下在使用Camera实现Y轴平移时的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_30.jpg?sign=1738870403-NCDQeRS54msWbKl4kRdE0MTjzLJcN1Un-0-53286d62dec5365e390c81a1262afd95)
对应的效果如图2-3所示。
很明显,通过Camera和Matrix实现的沿Y轴平移的效果完全相反。下面来看看2D坐标系和3D坐标系的区别,如图2-4所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_31.jpg?sign=1738870403-Cqp4xh7grxI0u4ztKpOPRLMycEzujKNJ-0-b4c4134f04bab129dc4e7276bc18d7ee)
图2-3
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_32.jpg?sign=1738870403-y4kQKlKVZK1LpAa0ZgXkQcxJEtnfU0I7-0-cee6f64a69d26e6ae95ad0ee6f6e7e4d)
扫码查看动态效果图
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_33.jpg?sign=1738870403-NVWhjmDR6V1m4nqltrWIPTJVC28gdgSJ-0-551cd66c59585b87ff1e4e519583de9e)
图2-4
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_34.jpg?sign=1738870403-uxd1oozBSyPGcCE0b6D8mhG4DwrPV6vp-0-53174b4ba5e2dba3b7b802df6b4ebb73)
扫码查看彩色图
很明显,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=1738870403-1cTeaw6v2ynSFXFOo1abG9I7Sn6TfVcG-0-71afbebe3d1d4ad2f615243136356232)
该函数主要用于设置旋转角度,参数具体含义如下。
●float degrees:旋转角度。
●float px:旋转中心点的X坐标。
●float py:旋转中心点的Y坐标。
在第2个声明形式中是没有旋转中心点的,默认会围绕控件左上角原点进行旋转,比如下面的示例代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_36.jpg?sign=1738870403-O0zY360LbkQruknRpPjaxrMYk9wea6VC-0-cf2710896b1d9d9da413fc5f618b3c77)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_37.jpg?sign=1738870403-k7UcsjzdovKIabhueMlIMKHwBucGTWRg-0-e2521ce3b865ab06c0af09dc0f1a2285)
效果如图2-5所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_38.jpg?sign=1738870403-7FnWyeVGSGIFohpwfsNUkCa4NYklsdrD-0-9e2c62af74ee93643b60af64ac66ade7)
图2-5
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_39.jpg?sign=1738870403-ZnZWDAtjwGz2CSQg2KsEpgM4bERoi6L2-0-59d62862b95b48355fc6885a0e8e21ae)
扫码查看动态效果图
可见,使用matrix.setRotate(mProgress)实现的旋转操作,是以左上角为原点来进行旋转的。
假如,我们将旋转代码进行变换,以(50,50)为旋转中心点:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_40.jpg?sign=1738870403-Z4vZwOnafGmj2Tfz9hjFr6cFFIu8GRAe-0-742b924152164982177d8c4400d036a9)
效果如图2-6所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_41.jpg?sign=1738870403-zQh3g331mlPpSxlyzM8TnMHkq2sj7Fl9-0-14f05a30ca3252d93a8ba20fed5de023)
图2-6
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_42.jpg?sign=1738870403-deFOhdM8PkhpDhLAsE0oybdcvLan8t3O-0-a318d7bda593a559d7221b5fcedaae54)
扫码查看动态效果图
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=1738870403-sy1W6qjF0A2Tsj4Rb8TBTKT1Osz8qh8Q-0-e98f6c66087bcdba0fb4703643cd8f77)
旋转相关的函数有:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_44.jpg?sign=1738870403-eZffadIPovkr87SNRGeJNbIqyQ5ifgBL-0-70c247132f81599fa571cfe4cd7371ff)
另外,还有其他操作方法,虽然此处没有提及,但凡是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=1738870403-62lg29g2BRjPqz84Db2tYvQvWvZDYLPX-0-f6d4ea8b2181b2e2a2d4c3a2138980b0)
在上面的公式中,Translate操作对应的矩阵的缩写为T,很明显,前乘的操作方式是原矩阵在乘号前面。
同样地,如果我们在原矩阵上使用matrix.postTranslate(10,15),那么矩阵的乘法次序如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_46.jpg?sign=1738870403-11DYngGzD1uUNRahPKbsfdaJ9UpfvIaf-0-e18433ce69d40ca642d1a650a5f85f02)
很明显,原矩阵在乘号的后面。
区分前乘和后乘的主要原因是,矩阵乘法不满足交换率。
再增加一点难度,如下面的伪代码,其中同时运用了多个pre和post运算,这时的运算顺序是什么样的呢?
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_47.jpg?sign=1738870403-JvFm8IBxC3bmiVJYjq8ttDjDnnvpouDy-0-0e3b384a3f39ecf34c4c177394bf8666)
假设Translate操作对应的矩阵为T,同样地,Rotate操作对应的矩阵为R。
下面逐步分析这段代码对应的矩阵操作顺序。首先是第1步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_48.jpg?sign=1738870403-sgn3wziuDYaYOG4CPDyxHoz8LQbfwxuE-0-da8509bee8e532be529ccbb4ce49586b)
这一步创建了一个单位矩阵,假设该矩阵为M,此时的结果=M,其中
表示该步的结果矩阵。
然后是第2步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_51.jpg?sign=1738870403-7x6I0sLMpNnLTY0er0FmuCLOqEsJbYRp-0-d28e435d27852f2c1e85a93f80ae47ea)
在原结果矩阵上前乘一个Translate操作,假设该Translate操作对应的矩阵为T1,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_52.jpg?sign=1738870403-9vLnwkH0OWn7ORteSlX00aXI6eJ0FD1P-0-b7ece2a8291700e26943f9bbd1b85f40)
其中是第2步代码执行完成后的结果矩阵。很明显,它等于当前的结果矩阵
前乘T1矩阵。
接着是第3步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_55.jpg?sign=1738870403-8iMC6hihuTLFk9RTtY8WDOstIOBCUK8g-0-3ad0f7a23c735081042b625a39b0a948)
同样地,是在当前的结果矩阵的基础上前乘Rotate操作,假设该Rotate操作对应的矩阵是R,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_57.jpg?sign=1738870403-K4WTynGaxmCo8ejHVPVOmmSGEJPrKTJs-0-77ee98873bc55e5b733373c9347df49d)
是第3步代码执行完成后的结果矩阵。
最后是第4步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_59.jpg?sign=1738870403-H7oDp4NdjGCLCWiPfsRG9TFzmnKeoo6y-0-76f3c1b8fbd8132d80121f4b6bef0801)
表示在当前结果矩阵的基础上后乘一个Translate操作,假设该Translate操作对应的矩阵是T2,那么整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_61.jpg?sign=1738870403-ikRRVXLEZPxY1KzEAboxEtHfahNItLy8-0-bb8176929aeffb9598939cde1b70cf24)
是第4步代码执行后的结果矩阵。可知,
是整段代码执行后得到的最终矩阵。
上述换算过程演示了矩阵的前后乘关系,以及如何通过公式表示整个过程,这个过程在后期代码中非常重要,很多时候,我们需要知道如何将想法转换成公式,最终通过代码将公式写出来。
2.2.2.2 更改旋转中心点
在第1章中,我们经常会在所有操作结束之后,将操作的中心点移到图像的中心点,即通过如下代码来实现,下面就来讲解代码的实现原理:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_64.jpg?sign=1738870403-BJLcJr8bc4K2HHUtWesIMEkuwHhcWFQC-0-a0b00b395b24947edeaec668d21b9396)
首先,针对各种操作,有两条基本定理需要知晓。
(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=1738870403-8Incnq4SRgsb9d9GSoO8QMF2hPXnAo5W-0-f096c4749ca673dbc16fa9286e681bae)
所以,如果对该代码进行扩展,改为任何操作改变坐标系原点的通用情况的话,矩阵乘法公式变为:
M'=M×T××-T=T××-T
其原理也很简单,先通过平移操作将原点位置移到指定位置,然后对图像进行各种操作,操作完成后,再把原点位置移回去。
相应的代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_66.jpg?sign=1738870403-fSHmprAh9ZAb87THGQ9CaFTRdq7mGhsp-0-a6c81d415ba535e974d4cbc67b448683)
上面的代码逻辑非常简单,就是从前往后,每执行一个操作都使用一个pre函数,这样写虽然逻辑简单,但两个调整坐标系原点的平移函数——preTranslate函数,一个在整个代码段的最前面,一个却在整个代码段的最后面,就公式而言不好记忆,所以通常采用这种写法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_67.jpg?sign=1738870403-2rSJWjsIK7NPzlBEg41CKuLs5m5yPTmA-0-d272977641f4a4ffecf2b47df2eb8de7)
即先做各种操作,然后使用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=1738870403-psDfAfZIUn9y1di1akcwn5cZm2VBO04l-0-2b13a6e612b3ada44e3ce5843b8944f1)
可以看到,函数名中除了有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=1738870403-FsJe3qiwFy0wTTuH69j387CBsx285qZV-0-6c1df2fd6bc2261d40131df627b98de9)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_70.jpg?sign=1738870403-9GB4g6RvZcFBAb2SYsWnTNAwYk13wft1-0-f59f0a21a8ad44301133ce59f2853272)
在使用testScaleView时(activity_test_scale.xml)进行全屏展示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_71.jpg?sign=1738870403-LgnIetXcZzy20YyXQ9GK82fQ03bkqDtp-0-d4acd29f5cc99ff49d9d49530d28860b)
效果如图2-7所示。
根据如图2-7所示的效果图,我们来重新看看在onDraw中具体执行了哪些操作。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_72.jpg?sign=1738870403-mQ5zl9jJ6D7u0TIHckXLWmrb4Js2YnM4-0-95b12bb4aef3c9b77a609cfc50430dd3)
图2-7
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_73.jpg?sign=1738870403-Bq4cLeNmwUlNnkutxthwj9yuMPK79ZRz-0-38c59e88e173c46f03f72d7fc34dac00)
扫码查看彩色图
1.移动坐标系原点位置
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_74.jpg?sign=1738870403-IsrXTiocCEKEM9czUl4AX1DlYWCgDwDo-0-279a3c4e8fa052f846865e4adc3b705f)
因为testScaleView是全屏显示的,默认的坐标系原点位于View的左上角。为了方便理解,先将View的坐标系原点移到整个View的中心点位置。
2.绘制矩形
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_75.jpg?sign=1738870403-PwbMRw1MIrNFT8E1UaO5UJzVPY2ugzM4-0-8275ef10b2e86cd37878a256241cf9b5)
根据最新的坐标系位置,绘制出矩形区域,如图2-8所示,图中标上了坐标系,方便读者理解。
此时画出来的是RectF(0,400,400,0)这个矩形,即黑色方框。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_76.jpg?sign=1738870403-CUpl4IlnVagPA7ClhNrvT8NOAUdBmloN-0-b7b70447cd755ca19b3234543969ce3c)
图2-8
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_77.jpg?sign=1738870403-ac6f9BqI5C6XAR0NrMKA4O34ePDznIoG-0-f7b86ef7c45ffe1a9ce66dacd1919ec0)
扫码查看彩色图
3.缩小标尺
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_78.jpg?sign=1738870403-ikxC8MUJPEuiHE3XYzymtYHmJww2VDor-0-058a09d88a89f947f197811b517eba54)
需要注意的是,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=1738870403-VYxVeGDXx55asDmKAH9vTa4O9LSeXyFf-0-138afc2c00813b235200a9831508e433)
图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=1738870403-gzLcQznPRVUPGWq0P7mzOdVoX6WViPku-0-cfc3207f96cf59c3f2775b499556b6ca)
此时,所画的矩形就是在缩小密度后的标尺上绘制的,绘制的矩形就是效果图中的红色矩形框。
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=1738870403-QMdT79RgxzTK2ac1HMhqPrJtqvG67I3B-0-7401a51a18098b5755f237dbf9ac0143)
这里其实只改了一句代码: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=1738870403-MYqLrUfwD2W5m2SfVxX8YH8PtxAQHZUi-0-a782cc8b192ab51145afd6ce98332137)
图2-10
左图表示正常情况下的X轴与Y轴的正方向,右图表示X轴翻转后的X轴和Y轴的正方向。
在这种情况下的效果如图2-11所示。
效果图不难理解,黑框位置没变,红框在X轴上进行了翻转,这就是取负值时的效果。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_83.jpg?sign=1738870403-K2H6Uyli0GajkLZQnaP9t9NMfOeVvSRr-0-021e3ec2dbf19c5ab198b58ed428dd3b)
图2-11
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_84.jpg?sign=1738870403-Mf2bn92uvCL0eMJf3c4jjuS8uoiCsZpN-0-c5651734c3717e25b2c886a95369b691)
扫码查看彩色图
2.2.3.3 缩放中心点的作用
从各个函数的声明可以看到,除了sx、sy外,还有px、py两个值,比如:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_85.jpg?sign=1738870403-jFBLDczKSGuFAlv4rUqncTUrpPcDjYpb-0-fec6dbf3526dd06e749050c16ba62b35)
从前面的内容可以知道,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=1738870403-ArUZdlpmenaa1qOtN8aRggadnpZN0MAa-0-b85c0f6d69b070fd973747aa668188a3)
如果深入Canvas的scale函数的源码中,就可以看到它的具体实现:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_87.jpg?sign=1738870403-fRjDphKy2cY66hGYQCFLFY0WL1uvXGTO-0-2d345e1308331eae5a3dfb6f3943522d)
其实这就是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=1738870403-aoKKsHQzlFc8Bc2nFXS5W6cE5bOZTjUB-0-ec0a35369f8a7bfdaa9cba1ac3a57ff0)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_89.jpg?sign=1738870403-tnK6jvYBDYeE74tqRcBtSDRTGiycUXDa-0-e8b79e0a7c2fe0dae5d34041a14a7a86)
此时的效果图如图2-12所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_90.jpg?sign=1738870403-Ur0wyWwbAyXNtCTr55mTCdxKPP2sYcAe-0-1c199abf244930c6ec54e603852ab020)
图2-12
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_91.jpg?sign=1738870403-W4obvyYZwDhF9y44yM5yfnmo5QHsgC1d-0-9b6092b88a4ea80dca0654c1d5e14500)
扫码查看彩色图
它的完整变换过程如图2-13所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_92.jpg?sign=1738870403-BeuApOXfiShStICz6rUSUtVlB2mo10sj-0-95a42b99c5f0493c25d883cc2ba750c9)
图2-13
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_93.jpg?sign=1738870403-CMNEChGe0SDFvMN66bH3wx4Eff5AjJ80-0-dca794f0f34711ae8a2dac7098d32f53)
扫码查看彩色图
从图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=1738870403-3ByEn5shfO7Xq18Kivuu2SZy1RQznCHK-0-b159dc5154488fc5c4e79f861eb6c798)
效果如图2-14所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_95.jpg?sign=1738870403-sAxRkj08Z6BRjp0uLFTYh2y5kXhrYGAW-0-9bbbe7b844e641f2a48c40458d8b812e)
图2-14
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_96.jpg?sign=1738870403-4xBy5BeZUUurM7JoYqx7FsYyI2Xs0xwJ-0-602b4581714e35ea4ce772605f0c7d3e)
扫码查看彩色图
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=1738870403-0dPURzdM4DpWqQ8q1knNns7J641tk5bm-0-ea3ebe5b4d0c94a5a77184acbad90a75)
图2-15
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_98.jpg?sign=1738870403-OUVb61i5nErQ5nM1UOGpmDenDJD2afDg-0-d6867c0dd194eb6ddbae436b3b6093ad)
扫码查看彩色图
X轴错切时,是保持坐标系的Y轴不变,X轴的值做线性变换,表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_99.jpg?sign=1738870403-XPcTCF7lwUf2hhZBJuy7i3lneXRN9DuJ-0-1c17bd48a8e584e9c67ccd010f0a7faf)
可以看出,对应到每一个点上,y坐标都没变,而x坐标都向后推了ky0的距离。所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_100.jpg?sign=1738870403-ulmrOnTbCFVldYi5asaUZCODGvkwG1WQ-0-0d4993a68f82e02a0507863ce7ef7d23)
注意变量k所在的位置,前面我们讲解位置矩阵的各个标志位时,已经提过该位置的含义,其主要用于标识SKEW_X:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_101.jpg?sign=1738870403-iSuAKHz6ABmau3bSR4aDtlCzWAGdjJmX-0-81fe5488275bae6f77b49f37a0ad8d28)
需要非常注意的是,在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=1738870403-1PYVfBPGAkDDixkJbHqw3tplsqb23FPR-0-fa29cb39bbda4992c522a4eb3c99ac49)
图2-16
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_103.jpg?sign=1738870403-pjMRTPNh1mRXZHr2c3Ci0HH2kkUQgXGo-0-8162b88808373dcbaa574608834b62dd)
扫码查看彩色图
同样地,所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_104.jpg?sign=1738870403-MfaJm25CghATvXYUODe590EiiFjDT9W5-0-65aaf9e3b7a34a369a8f80788e98ad9e)
同理,在Y轴错切时,改变的是X轴方向上的斜率。
X轴、Y轴同时错切(如图2-17所示):
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_105.jpg?sign=1738870403-aUfJ6pEA0ilfHxaes0yxlq42JeLOAIzx-0-8be6d51c0e51e88ed30a2e943b8a81fa)
图2-17
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_106.jpg?sign=1738870403-teIrCmMvmlWqQJztDI2Y1zo23QgfT8to-0-517d74d868d61ceea7968768b28e41c5)
扫码查看彩色图
在X轴、Y轴同时错切时,表示在X轴和Y轴方向上同时倾斜一个角度,很明显,两个倾斜角度是完全独立、各不相关的。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_107.jpg?sign=1738870403-7byTrk1DXaSSPNOc34ZchacawgLybuoi-0-8f6c612feee00207889d79463db4345d)
m表示X轴方向上的错切值,n表示Y轴方向上的错切值。
2.2.4.2 错切的用法
在了解了公式之后,下面来看看Matrix中Skew相关函数的声明及使用方法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_108.jpg?sign=1738870403-nKTH0cbX0GqDbnSgesRFFYfAMd3l6q0d-0-045aacaf882d5ecc350bb323447da6dd)
同样地,除了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=1738870403-bj8IHY9pJoWZWveMINpxNAc5LMMTNBSl-0-d2d0bf508e7fc327435e532972d3e08c)
同样需要注意的是,虽然第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=1738870403-4WMoT8BaypgcQxoaKrwVO89gZVoZy034-0-3c69de0ea4f3bc0b433595d35e65d464)
效果如图2-18所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_111.jpg?sign=1738870403-L8kvkvZuDnWWfiza9bzOZ9DFynHHajdu-0-704b202a9bff0eb78306479fd2269863)
图2-18
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_112.jpg?sign=1738870403-uBbaUvjJUcUHpOmmforHsaK3CNbcCR8S-0-b5831b7a70fca68b0781a3ab9fcf998f)
扫码查看彩色图
可以看出,由于Matrix操作的是坐标轴,所以在Y轴方向上倾斜45°时,所画矩形已经不是正常的矩形了,这是因为Matrix改变的是坐标轴方向上的倾斜角度。
下面再尝试一下matrix.preSkew(1,0,200,200);:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_113.jpg?sign=1738870403-qIdY70K7pzzI8fCOGewnFRxouh2Vm5Nq-0-5c42aba0f23ded857767cce077032cac)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_114.jpg?sign=1738870403-1E7V9GiUHpXg6rNFxo5yU9Id152yX5bh-0-c4640c6a0a3e7ba8bb5542419ab3f80e)
这里什么都没有改变,只是单纯地使用了Skew相关函数有错切中心点的声明方式,错切中心点为(200,200),效果如图2-19所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_115.jpg?sign=1738870403-BEnl8EDWuSJEnOxydHFaEbU6umyFFEBH-0-09545fbd8732b677477ee05d22aecf82)
图2-19
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_116.jpg?sign=1738870403-KWEswVErQfjxNgSIQU4qpHvkV1yv70EU-0-bd1ea3ad6c43383a51f35c8e012b3b49)
扫码查看彩色图
乍一看可能有点困惑,图2-20展示了以上完整的实现过程。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_117.jpg?sign=1738870403-xTH54WpZzy9dK6oQadQX7EJIh0qRkbZI-0-98235fcbdb4b13701dbea4956c9403e5)
图2-20
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_118.jpg?sign=1738870403-eWZzy7ly3V6Fl8Hm5as514w61oiLBCAx-0-7b6d73fc9f81ee681dad11b939f37905)
扫码查看彩色图
在第4步中,回移至点(-200,-200)可能会让读者产生疑问,下面我将这一步进行分解,如图2-21所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_119.jpg?sign=1738870403-jMvX0wvGqqemtCwY09KC3bbF37mCWnpd-0-66228a12c9f592279397af30dc125011)
图2-21
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_120.jpg?sign=1738870403-wLMqknpDb9dYEKgNEeLPoVlUT4UHztVA-0-60989958673a4bb89b16af096edc137b)
扫码查看彩色图
2.2.5 其他功能函数之setSinCos
setSinCos函数主要用于旋转操作,但它的函数声明比较特殊,如下所示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_121.jpg?sign=1738870403-JJUCrISj0sJ18y9BWGkM61GSoAUa5kWB-0-ad7c2b675d1e8d63470ab2b70a6a590a)
●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=1738870403-p5hxykghkM9u8G3WKA2l2CXrh4NW3d5O-0-a2406431a64adc940eaf88222dbde3b7)
在这里,我们就不重复讲解了,大家可以实际操作一下,然后利用画图解析的方式来复现一下它的操作步骤。
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=1738870403-66ZfBpm4SbdpQzDty3MJVj5sCTUKCPK4-0-c36807608673cad4490ed96f0f8014b0)
这个矩阵形成的原理如下:假设有一个点P,其相对坐标系原点顺时针旋转后的情形如图2-22所示,同时假定点P离坐标系原点的距离为r。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_124.jpg?sign=1738870403-UMq5X4Qx8lYBgxSKdt79BTK9PSIgwgCq-0-1f2697a0def000731c53ebe6bb2d2767)
图2-22
假设在未旋转前,点P所在的位置为(x0,y0),而点P离坐标系原点的距离为r,所以用r计算出来的(x0,y0)如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_125.jpg?sign=1738870403-f3thdOGkevBfX9BizZcm2FwNNM1rEUkY-0-32e1263079ba60e140ad1d9d05be736b)
假设在点P旋转θ角度后,其新坐标用(x,y)表示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_126.jpg?sign=1738870403-9t1IuTWDPjm6kmo0pPCCviTbyJBngtJz-0-457b91050e5339cb9ac9baf69ba9aa1a)
转换为矩阵表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_127.jpg?sign=1738870403-gMxgAHc7A8unbFUd8999LgXvijIP9OOh-0-cee3b45cbb2407466b374cd9b15096f2)
所以,setSinCos函数只是一种旋转方式。一般情况下,不怎么使用这个函数,而使用Matrix的Rotate相关函数。
2.2.5.2 setSinCos函数的用法
下面演示一下setSinCos函数的用法,将示例代码改为:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_128.jpg?sign=1738870403-inp222lWe6UcLtjYhdK2SYM13wWE4V2c-0-c3fcbc90a820f45ba0a9d0f07b8dd38e)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_129.jpg?sign=1738870403-re4Rg0jMA3mj8EXKSt3n4pNxH2yDeyiS-0-856b0ad48515275577edcbffaf667d28)
代码长了好多,下面逐步进行讲解。首先,第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=1738870403-vsYd1bjoiQNXGlvzk7jrHHL7ty9sTNEZ-0-d1875ede8d9454d9536a93bf5f6d5fb1)
图2-23
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_131.jpg?sign=1738870403-tzzETvgUl6x9UhooypOZ8DQkKYlVQGqX-0-671d6b672d588b99936541c9847fc779)
扫码查看彩色图
到这里,大概了解了Matrix中一些函数的用法,但Matrix中的函数不止这些,后面我们将继续讲解Matrix中其他函数的用法。