![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=1739260427-PNvra7h3JDStEIdemshsdeyH9CZ1RSRk-0-af83d1f6ea647141c74012972ccf6d40)
第一个构造函数经常使用,用于直接创建一个单位矩阵:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_21.jpg?sign=1739260427-IVqe6VkuvZT05FVJW2tlGZ8cNL7l4zXr-0-71d276edd5d0f44b791ecd64c7f8a28f)
第二个构造函数则会利用一个已有的Matrix对象,复制出一个新的Matrix对象,其内部数据内容与已有的Matrix对象完全相同。
2.2.1.2 reset
reset函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_22.jpg?sign=1739260427-aYy035epmtRRJdmtfapkC0K529gq64R7-0-1bbdd6225be97c8180b8669b60d0a288)
该函数用于重置矩阵,重置的矩阵为单位矩阵。
2.2.1.3 setTranslate
setTranslate函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_23.jpg?sign=1739260427-cEnNMnO3RKQ0VzsXdPxLfkTFT9YFNrSD-0-b9d16fe53397a984d863cf91488ff2ae)
该函数用于设置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=1739260427-ay4X4DnAY2dHSLhSMUMoV9d53yxXERNf-0-2708a778cd2afed944d8afd8efcf192b)
效果如图2-1所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_25.jpg?sign=1739260427-2nkmFi3IacRvpcTtCZGe4gPcGVuYu3h4-0-22b75ab09692dfeda4dfdd09da01ff5c)
图2-1
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_26.jpg?sign=1739260427-NjDgvczCgfPVfF28oKIcNzlJeXJ3bxr7-0-3fda3475d92172b7afab610e31c35488)
扫码查看动态效果图
修改代码,改为沿Y轴平移:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_27.jpg?sign=1739260427-X4o2ErfOn4491QAM4B8iRA9HjTEkCXpk-0-57178c8abcbae7903e85938505c353fd)
效果如图2-2所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_28.jpg?sign=1739260427-pflkfbj4VZJU4kI94QNGE1SUgRsdcjml-0-5fd3e8f1dca70dc7e8369c2d660698fe)
图2-2
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_29.jpg?sign=1739260427-SBVc4ABmw1YHbBBgCVZr6sv5SMpV9DyN-0-8e985376dbafdd4eba5bd75077fd43d3)
扫码查看动态效果图
我们回顾一下在使用Camera实现Y轴平移时的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_30.jpg?sign=1739260427-wS6q8yI4hVnYt4Wp61QDz9K8WWk0Ea6F-0-2bcf10e3cc91efe093cab5642b45b506)
对应的效果如图2-3所示。
很明显,通过Camera和Matrix实现的沿Y轴平移的效果完全相反。下面来看看2D坐标系和3D坐标系的区别,如图2-4所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_31.jpg?sign=1739260427-9A7PE5AVgCIDTmdpg3Ex5EfZzTj4xPLd-0-cf305e5c907d9e7d083322bd10702e63)
图2-3
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_32.jpg?sign=1739260427-vKuXAvXz7rXlW3LwR1txp0ckmYHwfTBi-0-6bfd5920a483a26f5ff0b6d9676e9a45)
扫码查看动态效果图
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_33.jpg?sign=1739260427-fVjRIcEiKX5mWbKqn6uftc3fWjm4HXoY-0-564244c512eb63fe46ddacf64a11e202)
图2-4
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_34.jpg?sign=1739260427-oMlAiu82OL4xOv7vBFDwm3Vl599xiNHi-0-2815bd5ed03e586cc9da10c771ee178c)
扫码查看彩色图
很明显,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=1739260427-Zzt4mh5Ly0HeFL4Lc99iQw5PnpLkHKRT-0-f482c4b12474f569e4e857968584567b)
该函数主要用于设置旋转角度,参数具体含义如下。
●float degrees:旋转角度。
●float px:旋转中心点的X坐标。
●float py:旋转中心点的Y坐标。
在第2个声明形式中是没有旋转中心点的,默认会围绕控件左上角原点进行旋转,比如下面的示例代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_36.jpg?sign=1739260427-HArtJZdKGiRyFpQ3LqQwiK3vJ1KPrd77-0-2f910bd71a6dba8a04b3eb67acf2f846)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_37.jpg?sign=1739260427-xVwsPdU86jbMps9MHwzyq0oNWujHHwIt-0-79abece4b9452530fda8228494d3bac5)
效果如图2-5所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_38.jpg?sign=1739260427-KIlmws1oPfrxBfNE7ni5StoFyEqpBwLb-0-b7277a83b78d2bf3276ff651438b18fb)
图2-5
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_39.jpg?sign=1739260427-6B29HXXuK4tFIHoOA8TmTlAt7No5Kad7-0-1970d9e3c40920d052b0bff1aed066d6)
扫码查看动态效果图
可见,使用matrix.setRotate(mProgress)实现的旋转操作,是以左上角为原点来进行旋转的。
假如,我们将旋转代码进行变换,以(50,50)为旋转中心点:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_40.jpg?sign=1739260427-1rukEpE7A4KPowxyu3k9iQWZTnsgSErz-0-780a9d051afe37e105dc6e4dc47275e4)
效果如图2-6所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_41.jpg?sign=1739260427-6EYxpsWd7bbLtkWPw5VvwuZhjd4yLilA-0-f79acc622cd771c42d74a84df66d14ec)
图2-6
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_42.jpg?sign=1739260427-VyYtSoaAIFlm1Tg88lJkQxlLu7HDHhAZ-0-3a9b78d5cec6870057d6e5bdbbd35e4d)
扫码查看动态效果图
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=1739260427-3N9TfcFYeOdRxlMvSBe1Ar1i9frSzuDC-0-a28038ce582ac352aa61fb386b9c6dea)
旋转相关的函数有:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_44.jpg?sign=1739260427-CcA3pmrYgd53OghGPa0ejknVGfKVxXr1-0-3eed1d837aa04e8e56876b16e26cfdba)
另外,还有其他操作方法,虽然此处没有提及,但凡是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=1739260427-N966qyMJPf7h2vjn1cwk9lR5rLv0W3ck-0-7ea89c4b22bc5ddddabb75fc7a24f51d)
在上面的公式中,Translate操作对应的矩阵的缩写为T,很明显,前乘的操作方式是原矩阵在乘号前面。
同样地,如果我们在原矩阵上使用matrix.postTranslate(10,15),那么矩阵的乘法次序如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_46.jpg?sign=1739260427-AIhXGq0sJO7z2PzO5tXcK7MoTcBpKwoK-0-50c0cabd8c6b9a40310db5d18b63efb3)
很明显,原矩阵在乘号的后面。
区分前乘和后乘的主要原因是,矩阵乘法不满足交换率。
再增加一点难度,如下面的伪代码,其中同时运用了多个pre和post运算,这时的运算顺序是什么样的呢?
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_47.jpg?sign=1739260427-x87KJR1LDjoRgjFTOlg5T3xwNNKvdHtE-0-e4fdde332c31709e600fd710bf1ece22)
假设Translate操作对应的矩阵为T,同样地,Rotate操作对应的矩阵为R。
下面逐步分析这段代码对应的矩阵操作顺序。首先是第1步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_48.jpg?sign=1739260427-xHccx140F01HrooUuuImYqHeq0hFsYho-0-7a6b9d4399ef5946a89464b4b675cdb1)
这一步创建了一个单位矩阵,假设该矩阵为M,此时的结果=M,其中
表示该步的结果矩阵。
然后是第2步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_51.jpg?sign=1739260427-CBO3DUeOGknO3ohwgO1rTZhF1g5PE2Q8-0-ab1ae1d519bf27d3811f74b9263ab847)
在原结果矩阵上前乘一个Translate操作,假设该Translate操作对应的矩阵为T1,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_52.jpg?sign=1739260427-yeq4Gqd5RKNP4osriZjcCaIvODcbyf1g-0-38e895e878d371c8b02c9c46f7aa9876)
其中是第2步代码执行完成后的结果矩阵。很明显,它等于当前的结果矩阵
前乘T1矩阵。
接着是第3步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_55.jpg?sign=1739260427-PlAu6tAHmcdoeScchIlC3oWkyXwqc1XN-0-8b888ddd657c7eb4403b0d3b16ac623b)
同样地,是在当前的结果矩阵的基础上前乘Rotate操作,假设该Rotate操作对应的矩阵是R,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_57.jpg?sign=1739260427-3CcRuuOgO8pQYdWjmP5hJWQrBt3daSTs-0-368bddd6687084021daa75fd5bbde7e6)
是第3步代码执行完成后的结果矩阵。
最后是第4步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_59.jpg?sign=1739260427-mpkUVGeJTqXr7Ojpqg3SJsAfPl6Ebs7X-0-4ed978031d12cc68c67721ea091954c7)
表示在当前结果矩阵的基础上后乘一个Translate操作,假设该Translate操作对应的矩阵是T2,那么整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_61.jpg?sign=1739260427-pffoWXECk4llgJqc3fqO7A1B9h8PT9RG-0-218d3886500731ec9425ba04f4c71dc5)
是第4步代码执行后的结果矩阵。可知,
是整段代码执行后得到的最终矩阵。
上述换算过程演示了矩阵的前后乘关系,以及如何通过公式表示整个过程,这个过程在后期代码中非常重要,很多时候,我们需要知道如何将想法转换成公式,最终通过代码将公式写出来。
2.2.2.2 更改旋转中心点
在第1章中,我们经常会在所有操作结束之后,将操作的中心点移到图像的中心点,即通过如下代码来实现,下面就来讲解代码的实现原理:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_64.jpg?sign=1739260427-57x8P0jnPlaDbFlTWEfGEmzrg2ltcXbI-0-09e7bd63543c36b9872580171f131a93)
首先,针对各种操作,有两条基本定理需要知晓。
(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=1739260427-H6YszWrQwLV72EaSeE3RaqvarNqsR57m-0-a12fcc0bf793ba1887cb85daffcf6fd1)
所以,如果对该代码进行扩展,改为任何操作改变坐标系原点的通用情况的话,矩阵乘法公式变为:
M'=M×T××-T=T××-T
其原理也很简单,先通过平移操作将原点位置移到指定位置,然后对图像进行各种操作,操作完成后,再把原点位置移回去。
相应的代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_66.jpg?sign=1739260427-1Zzc9UIKVCnkZ3lXaUjucI80IYsXUfD4-0-4fbbd9d08fe232a8f15bebfb2702a9ec)
上面的代码逻辑非常简单,就是从前往后,每执行一个操作都使用一个pre函数,这样写虽然逻辑简单,但两个调整坐标系原点的平移函数——preTranslate函数,一个在整个代码段的最前面,一个却在整个代码段的最后面,就公式而言不好记忆,所以通常采用这种写法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_67.jpg?sign=1739260427-tSUAeWqbnSM5gAMXOSB75zKgBZXXNSM3-0-15a1bf59a3a682483e74f1d1919ec893)
即先做各种操作,然后使用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=1739260427-5oLMXNyJuEDB8iXqhL5gXD93hVtPAvjq-0-76dd4bb91315c92592746087d86d3800)
可以看到,函数名中除了有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=1739260427-kDACVAQ8K7z51kt4wGXwkGHfXJpQ9SAu-0-c762b0949261f111cde9fce1592bd950)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_70.jpg?sign=1739260427-LcfiRutBNGI9zTnXZXq0xoVyIY3KoFf5-0-57da9c88a554f5bc957a88dcf847bdbd)
在使用testScaleView时(activity_test_scale.xml)进行全屏展示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_71.jpg?sign=1739260427-1SbgJ3xozFg7Sc2pL31WTVVj5YTRC6D6-0-bb485e52ada5762b47fc345737eb828d)
效果如图2-7所示。
根据如图2-7所示的效果图,我们来重新看看在onDraw中具体执行了哪些操作。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_72.jpg?sign=1739260427-jyMe50vf70EdUtWDrDh1CQW7qlCvi6S4-0-c6fcb75b87dc288326e7ee55a2b2885d)
图2-7
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_73.jpg?sign=1739260427-8O3J557ZRf2Tq0EQN1RifmZh3caPGwBH-0-18b9945c5be8dd0aabf4962563e620b3)
扫码查看彩色图
1.移动坐标系原点位置
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_74.jpg?sign=1739260427-vSIQIt5lsCjug6VEBrFusna2g3D1sNmI-0-71453d16fd719247715b5d52a07938e6)
因为testScaleView是全屏显示的,默认的坐标系原点位于View的左上角。为了方便理解,先将View的坐标系原点移到整个View的中心点位置。
2.绘制矩形
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_75.jpg?sign=1739260427-ess4tPQoXMkvMogsnJwyOztVF8uKtZLw-0-f889d04b32c95aef1186d0f42da3f59a)
根据最新的坐标系位置,绘制出矩形区域,如图2-8所示,图中标上了坐标系,方便读者理解。
此时画出来的是RectF(0,400,400,0)这个矩形,即黑色方框。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_76.jpg?sign=1739260427-scwcKokSRlx1kPmMJ6tyOg1bSMs0fYL1-0-ecf17fe91f787fd84ffb40ff5604a42d)
图2-8
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_77.jpg?sign=1739260427-Vg9ZRQfYmhxEl7BpNFaQYOpWMJw3Nh9V-0-1d2ca6e1b9b2cd911083c66d9a148b08)
扫码查看彩色图
3.缩小标尺
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_78.jpg?sign=1739260427-rEZyl0SvhxHZDv0AdPSTjxoMChlUdSzm-0-057759b3d4a7bed1ca4b559a072b1948)
需要注意的是,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=1739260427-gqAEUZQB88bFP3YeEHnVq2v9SqYUSXSL-0-c5dcb174cec41bcff76057eaa7e2debc)
图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=1739260427-0670po0nlaRfLYmmTE9f8ocu6DT5Jcda-0-34310fe7ed64789c42ebd74eff8a61d5)
此时,所画的矩形就是在缩小密度后的标尺上绘制的,绘制的矩形就是效果图中的红色矩形框。
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=1739260427-K79dT9mO7TcknY2tzYZRTNNTKRQ2Cw7n-0-2f00d63db2ba82ed1ddd94e3ee1070c6)
这里其实只改了一句代码: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=1739260427-5Z8HBkBeW8987bu4Am4oF0JiE0hVugGz-0-5e274a11378ae9bf30b064ddb44feb3b)
图2-10
左图表示正常情况下的X轴与Y轴的正方向,右图表示X轴翻转后的X轴和Y轴的正方向。
在这种情况下的效果如图2-11所示。
效果图不难理解,黑框位置没变,红框在X轴上进行了翻转,这就是取负值时的效果。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_83.jpg?sign=1739260427-D1HLiF9pa3IqOC6zDR5F3Dde5uL1a1PF-0-686232673c87891058d9dcfbad1fcf81)
图2-11
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_84.jpg?sign=1739260427-SGdhHA1zFKXman3Zjtk0BpLlcxKDPYih-0-8721ab8be64af141b88035e07d37724b)
扫码查看彩色图
2.2.3.3 缩放中心点的作用
从各个函数的声明可以看到,除了sx、sy外,还有px、py两个值,比如:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_85.jpg?sign=1739260427-BIBEjwlnZMa6urGKM6NQCw1JyBo9Pqhp-0-55230cad5a5edea380b8319b527bcd05)
从前面的内容可以知道,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=1739260427-shqVj2dWnid9veszcKL9BqaApyVSCoJf-0-b5453eb01ed3f6cf73aa7a51fc42d71d)
如果深入Canvas的scale函数的源码中,就可以看到它的具体实现:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_87.jpg?sign=1739260427-ZyO0g0SVQH4otUsTFwo35bSbMNhGgdqk-0-62f7450fbae0b7d99ae051a3b8710ed0)
其实这就是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=1739260427-KA6EWvrTOjwxjzCR3ERtA2sOejPbLSLo-0-927b2ac5fb8547da98a5bd0b549f73d4)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_89.jpg?sign=1739260427-qKhVvIpJ18F4boxYpcquhgFUBf13t9JS-0-9257984365d5bda89efcba48f9b945c1)
此时的效果图如图2-12所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_90.jpg?sign=1739260427-rMCv5xVnfaP32cEdLGgxUnCW9nWUrepd-0-a6e5719e3f3e44973a07301d4d32aef6)
图2-12
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_91.jpg?sign=1739260427-QXYA1R069AOomiB6VFibmY0XfKb0zzyd-0-205f4ff1fd48b6f46c545dd44073a0fb)
扫码查看彩色图
它的完整变换过程如图2-13所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_92.jpg?sign=1739260427-6gRDShEDFqNYpdmP6mSIWF5uL32fVNTV-0-d1262e4692cee3b2df447abd9ab57ada)
图2-13
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_93.jpg?sign=1739260427-2KKPRtGsvme6Sk5XhD1h4byJsRp8TgpF-0-ae88b04668f5da42b1ec453991c14ac0)
扫码查看彩色图
从图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=1739260427-lJAv0voHzhOgykQD3JwZShqrd1njOLxp-0-b0382c359adb06f12146c16fe6aeca5d)
效果如图2-14所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_95.jpg?sign=1739260427-t6JVkF0k8Bt07SgSyXQfH7ueca8ySBVy-0-3819d72dc5f091969fabc83e82745542)
图2-14
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_96.jpg?sign=1739260427-B3XXdFniFFmWT1gBUikGtDRIqdiaAVPd-0-94b0ba21178719c1b54e2baf0ef1fc10)
扫码查看彩色图
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=1739260427-I3TgGi9lkH3lbHrVNhSwLEaM8NAteuPG-0-65f93e6757412de4e509298761fd56d3)
图2-15
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_98.jpg?sign=1739260427-UlleepGFGyJ9O0Y0fTfaYH4pmGPtKUZ9-0-220c036393d9eeefcfc8ac941acbd9a6)
扫码查看彩色图
X轴错切时,是保持坐标系的Y轴不变,X轴的值做线性变换,表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_99.jpg?sign=1739260427-X7ciPNZu69Qa0TL2gcPiCZnw4kFJn1Sf-0-47f4a106223ce3bd1780c6fe8b272fc3)
可以看出,对应到每一个点上,y坐标都没变,而x坐标都向后推了ky0的距离。所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_100.jpg?sign=1739260427-OMITdV2xKJN5cM3djqr0yG8KQNUDKwq6-0-2fa37a39d8ad0d591d6e260064aa5df0)
注意变量k所在的位置,前面我们讲解位置矩阵的各个标志位时,已经提过该位置的含义,其主要用于标识SKEW_X:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_101.jpg?sign=1739260427-DxkphknHsf5Evu2uDlbIy0Ij6w6zfi8B-0-8d71b834257723e0f8d6eae133d064bb)
需要非常注意的是,在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=1739260427-4TICCRGMFVp3jBTRbJzjERa1bEqZYnLT-0-3cccc2fb86eb4b35c27fa0722a41d17f)
图2-16
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_103.jpg?sign=1739260427-RWKOaRYKqWHb51q8tC9OY7VuRv0abzHR-0-7a74b5f2a1d91f6b4aaba0b07fc9ad86)
扫码查看彩色图
同样地,所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_104.jpg?sign=1739260427-beMmuHi7ZvDgsMyLI6PekLjntrND4LhE-0-e1cdb964b9a06a629f23e80abca5c650)
同理,在Y轴错切时,改变的是X轴方向上的斜率。
X轴、Y轴同时错切(如图2-17所示):
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_105.jpg?sign=1739260427-rPaJM6nEJWWF7cOXDBBeezhNzIeKZCHX-0-9961f338fca462359e02ca8f3a824cce)
图2-17
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_106.jpg?sign=1739260427-rFWZlR3FOtk5viv1K6VtSqkHoCuONV08-0-7187c7b7083289f9ccbb8663b4a7d034)
扫码查看彩色图
在X轴、Y轴同时错切时,表示在X轴和Y轴方向上同时倾斜一个角度,很明显,两个倾斜角度是完全独立、各不相关的。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_107.jpg?sign=1739260427-UercBmuB3lGt3yJoUK4ywyQMwAYzq0Fw-0-39d8dae747fd391917104ab88db48bc5)
m表示X轴方向上的错切值,n表示Y轴方向上的错切值。
2.2.4.2 错切的用法
在了解了公式之后,下面来看看Matrix中Skew相关函数的声明及使用方法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_108.jpg?sign=1739260427-3pB9xBlfpCg8X7EsNrilTXBtOErB5Z28-0-9993b99efe68eb4b06c19f903e8f1701)
同样地,除了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=1739260427-Rzq7EwTvRVyIBqDjEndgHPjGWpubtnuk-0-46f3afafd9e139c88d5578553f043eb2)
同样需要注意的是,虽然第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=1739260427-H4m5P7qwc5jWDOCckWILYidc5vTaSaoM-0-85e7565308de91fe4d9a874071bcdc7a)
效果如图2-18所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_111.jpg?sign=1739260427-LR9Wggots8XEpjayqSnWqxfJ3SEpkMBi-0-a7e3cb548ac96c357d059c3937b8c26b)
图2-18
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_112.jpg?sign=1739260427-IvihlPdrNA7ttxMisfytWdt4jrXuhK7e-0-c446ecde2e50211edb6028da1f85351f)
扫码查看彩色图
可以看出,由于Matrix操作的是坐标轴,所以在Y轴方向上倾斜45°时,所画矩形已经不是正常的矩形了,这是因为Matrix改变的是坐标轴方向上的倾斜角度。
下面再尝试一下matrix.preSkew(1,0,200,200);:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_113.jpg?sign=1739260427-L5DBgxHl4b48FICFrN18JzMww1Eek0Eo-0-1ca7438a0c5836bace1fb061d5d5e73a)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_114.jpg?sign=1739260427-XLPTT2gvyNeYdyvCs9yWuTFq6s7tZiHN-0-4cc6918d4774d28097374846dce1d2df)
这里什么都没有改变,只是单纯地使用了Skew相关函数有错切中心点的声明方式,错切中心点为(200,200),效果如图2-19所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_115.jpg?sign=1739260427-t93CXfVAt9OSaMDrkoBf6DwIxFesislm-0-586c16678d8a27add181c8eed05efcdd)
图2-19
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_116.jpg?sign=1739260427-MnbrsiKthuXlkvPuQljnfWFDbzVA8G1E-0-2e854506a2b93d02588659c48fe5aa4b)
扫码查看彩色图
乍一看可能有点困惑,图2-20展示了以上完整的实现过程。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_117.jpg?sign=1739260427-AglHfmk97JecJNvgFqqUFESzGeRPToN4-0-922399759b99ec510b34891158b41112)
图2-20
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_118.jpg?sign=1739260427-m4Id7isM9cyQJyPinHF2aHMTLFq6Hz9G-0-5a85e384b96e557edef32338d06a7469)
扫码查看彩色图
在第4步中,回移至点(-200,-200)可能会让读者产生疑问,下面我将这一步进行分解,如图2-21所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_119.jpg?sign=1739260427-mp2gk54nGGGk2LbB1K32c1bhaIeUV5fi-0-e770abe7fb65fc12f222ef0082b267af)
图2-21
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_120.jpg?sign=1739260427-N5Dtz2WQRjsaQoSLOUzj9gCGg0buAt3G-0-1b18c0bd3f80d19c59e74c1da100c1bb)
扫码查看彩色图
2.2.5 其他功能函数之setSinCos
setSinCos函数主要用于旋转操作,但它的函数声明比较特殊,如下所示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_121.jpg?sign=1739260427-9hUz8uQz64yjQlRd1hWrxwjIL1Y6tvLl-0-bffb95c09f51234f62543bba3d95f50f)
●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=1739260427-pFgzr8VnzQIxn8YqyRJaFfrcrQdFXMf0-0-6594c8a337627c1375db6e4416439cd8)
在这里,我们就不重复讲解了,大家可以实际操作一下,然后利用画图解析的方式来复现一下它的操作步骤。
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=1739260427-rEj4mD0Nqeg4c54YGdKZuYOLWpwkuNES-0-0f7e871f499d82bfa71f113bb1bbb7e8)
这个矩阵形成的原理如下:假设有一个点P,其相对坐标系原点顺时针旋转后的情形如图2-22所示,同时假定点P离坐标系原点的距离为r。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_124.jpg?sign=1739260427-BffuCZdcpUkd7VVmpQdVW50JoJcPltKO-0-20270db66462123ff26a90735630ae53)
图2-22
假设在未旋转前,点P所在的位置为(x0,y0),而点P离坐标系原点的距离为r,所以用r计算出来的(x0,y0)如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_125.jpg?sign=1739260427-WOlVkWM9mLfdj0WIm90QD71cZIHI2ikO-0-90cb41661f731d9cf65864c8c4f7e6f7)
假设在点P旋转θ角度后,其新坐标用(x,y)表示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_126.jpg?sign=1739260427-6jzfLpVkipj2g4fJMGny1m5dVqmMKPvh-0-41c7f8f634d0e88a9d0e778ade88c46a)
转换为矩阵表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_127.jpg?sign=1739260427-77217JSmbmSJaIzxBqTi3mlIHOCYxpJq-0-0f4fa974224cb6127d1e524d0a10555e)
所以,setSinCos函数只是一种旋转方式。一般情况下,不怎么使用这个函数,而使用Matrix的Rotate相关函数。
2.2.5.2 setSinCos函数的用法
下面演示一下setSinCos函数的用法,将示例代码改为:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_128.jpg?sign=1739260427-pIkYVWcMdifZB2O4MU0VIZAwVAZncrTD-0-9cce7f07d43f4479cfb81e43ec59d635)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_129.jpg?sign=1739260427-Egyez2sgC2lxQb7zS9uSWhOnsvTYXQjg-0-ffcfcebe43018230d4a4527919a1006c)
代码长了好多,下面逐步进行讲解。首先,第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=1739260427-YLEOeBiYkomuYGbOv34vNXnFcj4uBy3A-0-e3e78ea655c4476790cf1eb19bad1e50)
图2-23
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_131.jpg?sign=1739260427-EBDAwjozliqrmyQ19oFCl3YsHp94hcEz-0-6141519ec5d391e7376259667c75e19a)
扫码查看彩色图
到这里,大概了解了Matrix中一些函数的用法,但Matrix中的函数不止这些,后面我们将继续讲解Matrix中其他函数的用法。