![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=1739289905-63jYNjKeQleUtnWOaOAHzmv8fIW6M9Bh-0-11be5f0703d03cbc26f03aead48866ff)
第一个构造函数经常使用,用于直接创建一个单位矩阵:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_21.jpg?sign=1739289905-NpBAg8yGHQ8AMcgBP8pchw0IwAZUn3La-0-8aefc47565d7c1b234206d2b13f66151)
第二个构造函数则会利用一个已有的Matrix对象,复制出一个新的Matrix对象,其内部数据内容与已有的Matrix对象完全相同。
2.2.1.2 reset
reset函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_22.jpg?sign=1739289905-pZrAtMdDnRbUlDmTYrxNifb8LM3v69eV-0-63800b726f3d7a495d5ecc6334c8f36f)
该函数用于重置矩阵,重置的矩阵为单位矩阵。
2.2.1.3 setTranslate
setTranslate函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_23.jpg?sign=1739289905-OYLc3ZYbKZqk01RWmNxi9tyqlj67NDXW-0-0507e59e40d8e6ed769ddc515f6fde56)
该函数用于设置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=1739289905-n4V6KNa3RS6tKBPTgpFViFYXk67bAFS5-0-9b684d128621bc4763c01a330effc8f4)
效果如图2-1所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_25.jpg?sign=1739289905-xveZDbJXrJkfnJmNLSR45xQBLqK5l2CF-0-7da0e41ccca50ca4e41c3f1c07c839e3)
图2-1
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_26.jpg?sign=1739289905-5jd5pN21bPYJJD75FsgP2uJcBsQWABlR-0-353c52ba14e26fcfd25e9437cb7949a9)
扫码查看动态效果图
修改代码,改为沿Y轴平移:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_27.jpg?sign=1739289905-rDWBBi4n1p6pNInNvE75OCPkRlvJujxs-0-26d54b5302e65e7df21c5f619178faed)
效果如图2-2所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_28.jpg?sign=1739289905-W1JRdL71GQiCRCMqnXDzc7e4fsLeZmqg-0-6b2d33e36c64ad2db38cc9fa65288f45)
图2-2
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_29.jpg?sign=1739289905-1HnJjFwwQPWogjSPRV5h6FLuzPSoWZdf-0-61eac64ed11ef87469aed37197f1b6f7)
扫码查看动态效果图
我们回顾一下在使用Camera实现Y轴平移时的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_30.jpg?sign=1739289905-2XG96WsU9H6NyPZFQjgNARfRL299LHmi-0-1b3351fc2a751fba34c981ca7e4647ad)
对应的效果如图2-3所示。
很明显,通过Camera和Matrix实现的沿Y轴平移的效果完全相反。下面来看看2D坐标系和3D坐标系的区别,如图2-4所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_31.jpg?sign=1739289905-yVOG1aSZ8VbOop6OqeVrqFDKTWZhCy2m-0-232eaf45e7f61cba94f3ebded58adff5)
图2-3
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_32.jpg?sign=1739289905-L0VxAzJRWLvKQuLTbHFNDadIZLBSPBXz-0-b4be517a21c6af4f2eacb6954981d319)
扫码查看动态效果图
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_33.jpg?sign=1739289905-tNqvZDX6er5DWnYuR44LNLaRXpRpyhTF-0-6eb0123140c05d2be56cec5be35df989)
图2-4
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_34.jpg?sign=1739289905-dQcmhWJrJWIgWYsSnS8FODlRzcILMRIB-0-15427102359b0f588672ad8633fa66f5)
扫码查看彩色图
很明显,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=1739289905-FgOaoa4pcwZS9DLlFxwD1RY5GdttsjZT-0-08014029c4f0d1011118316cf7c6dc2d)
该函数主要用于设置旋转角度,参数具体含义如下。
●float degrees:旋转角度。
●float px:旋转中心点的X坐标。
●float py:旋转中心点的Y坐标。
在第2个声明形式中是没有旋转中心点的,默认会围绕控件左上角原点进行旋转,比如下面的示例代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_36.jpg?sign=1739289905-htWw9VbeVZTiENIdoZA7ePGWD5jHlblV-0-f9d94ca7ab3daa9562e213d21b882cf8)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_37.jpg?sign=1739289905-KvZy4s548DA2hm6ChOBAZGNB04LmRRtJ-0-b809ddfa54145676c4f14d5b5b565bbe)
效果如图2-5所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_38.jpg?sign=1739289905-FV3izmjhdT5GkuwzTWAU3VAVKQdnGRK0-0-fecf793aaa64920c02ccb8a169895293)
图2-5
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_39.jpg?sign=1739289905-CnnxadjNuBWfEEIGbF5MpJSkuAf3ndn7-0-6dded2484f1b8846ceb78492634a7e7b)
扫码查看动态效果图
可见,使用matrix.setRotate(mProgress)实现的旋转操作,是以左上角为原点来进行旋转的。
假如,我们将旋转代码进行变换,以(50,50)为旋转中心点:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_40.jpg?sign=1739289905-kIIwp2XcIKCBwM1BRjxwgmwAT2GZ2Lhy-0-0675b377410cab8633936737bc6c3038)
效果如图2-6所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_41.jpg?sign=1739289905-n12enAoIffc8a7H3AMSFj7xFpGNY7t4I-0-62c3fee51f4c0918e5e7bb69019315f5)
图2-6
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_42.jpg?sign=1739289905-28ZqI9U77uZM8zEoCHfXyCmwuoub8HDp-0-e4c9309a0979b5c556e29e59e7ee4c28)
扫码查看动态效果图
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=1739289905-5n94b8RUmfs2NbloQ4c0H7ZSsIH0vyQe-0-a9436711bdd8ebbdb4efa549c2251078)
旋转相关的函数有:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_44.jpg?sign=1739289905-jQtiNh967qbSlTnawxrVtpTsioUhzSgj-0-8332f52188905c6d993cc3f9ed8756d9)
另外,还有其他操作方法,虽然此处没有提及,但凡是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=1739289905-MtR8qbuldBeoyecdbwbNYUPefXU6o3E7-0-a1abfd4aefd2554db94399e1da135aea)
在上面的公式中,Translate操作对应的矩阵的缩写为T,很明显,前乘的操作方式是原矩阵在乘号前面。
同样地,如果我们在原矩阵上使用matrix.postTranslate(10,15),那么矩阵的乘法次序如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_46.jpg?sign=1739289905-hesRI8jybRohNO76FvuJesHr04pLNjFU-0-3df31000dd5ca4478a4a0f2b88fb7689)
很明显,原矩阵在乘号的后面。
区分前乘和后乘的主要原因是,矩阵乘法不满足交换率。
再增加一点难度,如下面的伪代码,其中同时运用了多个pre和post运算,这时的运算顺序是什么样的呢?
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_47.jpg?sign=1739289905-0X3oD1jCAZFmZMFLZudzvKyx3GyspvHd-0-c307e493c5ba00aa0a901f6413a32e13)
假设Translate操作对应的矩阵为T,同样地,Rotate操作对应的矩阵为R。
下面逐步分析这段代码对应的矩阵操作顺序。首先是第1步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_48.jpg?sign=1739289905-USraHiyqS49Qz6vfYRF6snOTrSKe9Jsz-0-0ef8decee509ccc87ec31e977b5a94fb)
这一步创建了一个单位矩阵,假设该矩阵为M,此时的结果=M,其中
表示该步的结果矩阵。
然后是第2步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_51.jpg?sign=1739289905-t3NLPG492QhempXOPKi0wUYK22sLh1vG-0-551004a0835723263cfbc20bae10b3f0)
在原结果矩阵上前乘一个Translate操作,假设该Translate操作对应的矩阵为T1,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_52.jpg?sign=1739289905-9HQdDbRiXLQxXBb0PfgC1dmYMeKUgBZj-0-217e3128e6899c4beb29e5111393d07f)
其中是第2步代码执行完成后的结果矩阵。很明显,它等于当前的结果矩阵
前乘T1矩阵。
接着是第3步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_55.jpg?sign=1739289905-umB86dtcb96eSsD11FopKb2j4MRPRmfc-0-c94a3b186ac6b1609183e9fadb603b38)
同样地,是在当前的结果矩阵的基础上前乘Rotate操作,假设该Rotate操作对应的矩阵是R,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_57.jpg?sign=1739289905-SdufrPka9r8qJeWjC9TX1oGaabD0fi6B-0-b468752b71eecbe007c540feefc25779)
是第3步代码执行完成后的结果矩阵。
最后是第4步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_59.jpg?sign=1739289905-3XM1Q56tOSNx7PXTywWdkYipVS1o3iGd-0-4a258232d4bf0a02fd9834e074afac76)
表示在当前结果矩阵的基础上后乘一个Translate操作,假设该Translate操作对应的矩阵是T2,那么整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_61.jpg?sign=1739289905-a17qZbj3GsHMBTDAsNPc8NCm3e6cYPLo-0-c37acc5524aa5ae4251132119013a662)
是第4步代码执行后的结果矩阵。可知,
是整段代码执行后得到的最终矩阵。
上述换算过程演示了矩阵的前后乘关系,以及如何通过公式表示整个过程,这个过程在后期代码中非常重要,很多时候,我们需要知道如何将想法转换成公式,最终通过代码将公式写出来。
2.2.2.2 更改旋转中心点
在第1章中,我们经常会在所有操作结束之后,将操作的中心点移到图像的中心点,即通过如下代码来实现,下面就来讲解代码的实现原理:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_64.jpg?sign=1739289905-GIgM8YZ8mZBeyQ8M0OnYXBdETfNB2bhi-0-e6b3b288b6f1437bb6f2a4d21e8b92f8)
首先,针对各种操作,有两条基本定理需要知晓。
(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=1739289905-NDqvSNRJ5PWVPqe97cq1nERCyEXKYMRk-0-5ecffc1e3b04851c73dd8c3f982ef30c)
所以,如果对该代码进行扩展,改为任何操作改变坐标系原点的通用情况的话,矩阵乘法公式变为:
M'=M×T××-T=T××-T
其原理也很简单,先通过平移操作将原点位置移到指定位置,然后对图像进行各种操作,操作完成后,再把原点位置移回去。
相应的代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_66.jpg?sign=1739289905-uY1ZWmsmAgzXBik0zZ7QL209qgSJIWGp-0-c73ba5880681352f742c4dc84e819895)
上面的代码逻辑非常简单,就是从前往后,每执行一个操作都使用一个pre函数,这样写虽然逻辑简单,但两个调整坐标系原点的平移函数——preTranslate函数,一个在整个代码段的最前面,一个却在整个代码段的最后面,就公式而言不好记忆,所以通常采用这种写法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_67.jpg?sign=1739289905-1tW9XZksNionvaXwX5exIcSk18XgKd8d-0-1c94beb97202c31cfce4e82d03701169)
即先做各种操作,然后使用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=1739289905-NGkhPVaWQ0LT1jcwNv3j1auscrhp30IJ-0-36c08fb864f6c46dd42c02480ab965ed)
可以看到,函数名中除了有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=1739289905-1MVq4TcsX6zlEhG6KWMVNWHolrUbSgKy-0-23b99e5be83df1a49dbc8f6980c672ca)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_70.jpg?sign=1739289905-pRdQ5RBdv4fBD1C2w9jOvXc3E3hRJdol-0-0236cb1b5925cb958e856a2b55357630)
在使用testScaleView时(activity_test_scale.xml)进行全屏展示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_71.jpg?sign=1739289905-S5ADRvpgS7SDOKWTeiIzrF2QOaTmYnds-0-813ea4f7067ad7c3902029806068e562)
效果如图2-7所示。
根据如图2-7所示的效果图,我们来重新看看在onDraw中具体执行了哪些操作。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_72.jpg?sign=1739289905-Y37cLZv4ou2KXJW5JZ8SN8WXb3x4wsxY-0-893daef365c5e0d208f7b4c57d27307b)
图2-7
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_73.jpg?sign=1739289905-V4ugrQ7onNuLW9SZSwHdVC8tegKnSHcN-0-9bb1989a43deca137e0638e663d9ca83)
扫码查看彩色图
1.移动坐标系原点位置
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_74.jpg?sign=1739289905-DIY2oQIx5nLXp8kHIKtEZFr8nbL4G85S-0-ff013ccf993a80f8f929db336c2b6f19)
因为testScaleView是全屏显示的,默认的坐标系原点位于View的左上角。为了方便理解,先将View的坐标系原点移到整个View的中心点位置。
2.绘制矩形
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_75.jpg?sign=1739289905-Cpbxu9U4DkaZSScn3PVuymfUNveNwDvc-0-abfab68ec420d1cd09bc6be4a618327d)
根据最新的坐标系位置,绘制出矩形区域,如图2-8所示,图中标上了坐标系,方便读者理解。
此时画出来的是RectF(0,400,400,0)这个矩形,即黑色方框。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_76.jpg?sign=1739289905-hsi4QZYKmCsbnR2Zup8Q7yEfIWxYN4yH-0-03bdac6ae78568ba84e963df9bfc58a4)
图2-8
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_77.jpg?sign=1739289905-w40t1fP5NM0Ryfuju7z6o35ebXPmGOfN-0-99d41f7d15222c24137f67762a6e33bc)
扫码查看彩色图
3.缩小标尺
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_78.jpg?sign=1739289905-ng0xyhpmkCHQsfhDFQNUVYr9ucLrMJAl-0-622be8dde92c2d301191e3a19d3d79d8)
需要注意的是,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=1739289905-0tPd6MKQjGouOl6Y6BilgHh63FU4HkUR-0-4b02a3821db2a2e321d0900915851517)
图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=1739289905-9M6SE3pyffCeyD7TMXMyXpVFT81tWkpI-0-25d5f76fe35a30c58bddf8383c68a947)
此时,所画的矩形就是在缩小密度后的标尺上绘制的,绘制的矩形就是效果图中的红色矩形框。
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=1739289905-hOp4ZJMBI10ZQ7Jao5UuCYamL1GB2lqD-0-3b36a86e41c2579c57db77d9eedd72a6)
这里其实只改了一句代码: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=1739289905-KUEhAL01t03TncHvpydyADzECUqe7ID0-0-cc625b8f7072abc7ef9553ac3b959ad5)
图2-10
左图表示正常情况下的X轴与Y轴的正方向,右图表示X轴翻转后的X轴和Y轴的正方向。
在这种情况下的效果如图2-11所示。
效果图不难理解,黑框位置没变,红框在X轴上进行了翻转,这就是取负值时的效果。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_83.jpg?sign=1739289905-sO5affsByB11LSUPeaerTrc8aEJHGKN5-0-5ffe9b417632a8ac3d127e7f1b536bf6)
图2-11
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_84.jpg?sign=1739289905-yIVKiHRAqnOUIQSHKFZd8VjmZcHowjzo-0-d3bef66cf8fe2cc420b5551403a7de7c)
扫码查看彩色图
2.2.3.3 缩放中心点的作用
从各个函数的声明可以看到,除了sx、sy外,还有px、py两个值,比如:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_85.jpg?sign=1739289905-cYFR6ZQa6IDV6C8TNfXhLhmyw0h1LXvX-0-8f96ba77df64121c0560ecd4c52c69a4)
从前面的内容可以知道,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=1739289905-mhBOHtAxgC0KeKY33UBiDIdAXl1rT25g-0-4d3ef340622a1292c4be78ff306fa0e8)
如果深入Canvas的scale函数的源码中,就可以看到它的具体实现:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_87.jpg?sign=1739289905-b1ibKSE8kldSVRgVChpuz791KrvN2OoL-0-52a01ebc5d8096df63f05dddd52dc8f0)
其实这就是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=1739289905-GMHUJWTKK0IPCTzATqktrcU0faIkCdJE-0-7bd0d8d4adaf27665a1aa98f8aec9525)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_89.jpg?sign=1739289905-nZ5iGfVPUQRUk2snHThWw6oxF81RNKC0-0-684b2448531d5aab0b1550e9f8c84023)
此时的效果图如图2-12所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_90.jpg?sign=1739289905-T7BT8dgTdTteLMyIES1pJXbzcwkhgTwi-0-fbbdd0b71355069cc87a43761db31739)
图2-12
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_91.jpg?sign=1739289905-WR9tAYbgsNTUf1owjKFQdJeYAUvD7Tp8-0-f07807d3e7a9c4c14768743c065b7abb)
扫码查看彩色图
它的完整变换过程如图2-13所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_92.jpg?sign=1739289905-7jnikvvDQe3R8IXW8wbolkBhsDqw2cn1-0-b976dc17c5bccf67e8ebea6c100a9ff0)
图2-13
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_93.jpg?sign=1739289905-JEaBocK7vaFRDBElSU4LvRa5iwEt1ZoJ-0-c4aa76148c20d5abe1646d67edec2bf0)
扫码查看彩色图
从图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=1739289905-7FiyeGfoAbsNBgyj07puE1nymSKmF785-0-c50192d224c2dfe37d83bd1828ec047c)
效果如图2-14所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_95.jpg?sign=1739289905-6welDsRxkPg8bppUDNaY6a1dQJyPNd1t-0-aa1404c47276397a7669c2865837dcf9)
图2-14
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_96.jpg?sign=1739289905-VlWeuuXJdXKYM4ARgndbsiAOoqwqzTjw-0-d994523c449597a809a58ac64084ca95)
扫码查看彩色图
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=1739289905-geLY0aaeqDdcebkKjA3fd80rNAOqNsS4-0-aa4872a39d8fe64644ecae8911be8285)
图2-15
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_98.jpg?sign=1739289905-bvdd7So0dcxzu8u9sJ1OAHcuGbUu3nGr-0-b2f902c99d0764cd8786dfd265440f04)
扫码查看彩色图
X轴错切时,是保持坐标系的Y轴不变,X轴的值做线性变换,表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_99.jpg?sign=1739289905-ExWzqlTy19muPsGjBw8YMyTIIaNmr8Xl-0-06ef7c15a2b52a566e83528cd7c078b0)
可以看出,对应到每一个点上,y坐标都没变,而x坐标都向后推了ky0的距离。所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_100.jpg?sign=1739289905-5ILmd5Bg01gd6xfVKLB0u8auh9dVvsbM-0-0609d5abbffafc07dfb369cfc1a1d362)
注意变量k所在的位置,前面我们讲解位置矩阵的各个标志位时,已经提过该位置的含义,其主要用于标识SKEW_X:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_101.jpg?sign=1739289905-mDgfbygFoPxnRlOmceyq3vVbPQBOfk3U-0-879b0134ffcbb34bb9d9fa7399781776)
需要非常注意的是,在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=1739289905-9vqu7dq9dF7smmc5gKCej6JnS2Cx1FWL-0-909c481afbae26a5347fb08ddff3f9dc)
图2-16
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_103.jpg?sign=1739289905-hryJjloj2HX4nvJRuwJUZs0YEHsRUiiJ-0-43fcbc79534656b9b6f3d07b190ed1ef)
扫码查看彩色图
同样地,所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_104.jpg?sign=1739289905-BavWZ1ULhJm4slMcw5kXOGNE9GP0ZL3U-0-91175f24a5b17123590da60075d3098e)
同理,在Y轴错切时,改变的是X轴方向上的斜率。
X轴、Y轴同时错切(如图2-17所示):
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_105.jpg?sign=1739289905-sdnxPH3816z9DNtMVZE1EebKcyK13f3I-0-57d0494f6de606ecb9ef47b1b5832664)
图2-17
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_106.jpg?sign=1739289905-yIQZqqtgMHHMx2OGaMyiSxABXNsmlAFV-0-9a366fda219e335abd830d3e27a708a6)
扫码查看彩色图
在X轴、Y轴同时错切时,表示在X轴和Y轴方向上同时倾斜一个角度,很明显,两个倾斜角度是完全独立、各不相关的。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_107.jpg?sign=1739289905-SrlESsoYuTTiLWJaoeJXtSHTKInFa80A-0-6fb7aaf59628e6418f801b34c2ee6bf7)
m表示X轴方向上的错切值,n表示Y轴方向上的错切值。
2.2.4.2 错切的用法
在了解了公式之后,下面来看看Matrix中Skew相关函数的声明及使用方法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_108.jpg?sign=1739289905-w7fRwg7v1gK7Ufk0fWZopGPPD6Ppie4B-0-dd64ab4ff3d83a12931324ab1d97ac96)
同样地,除了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=1739289905-iLQTrDHrX2ZoePts8gdCrDZp9pwgbX9u-0-779f51d71d61126b50c46da8078064b4)
同样需要注意的是,虽然第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=1739289905-tdDPYyH4GuHroXludJHSL42wYl270erk-0-90615e7b2dd4f1aba3334a88326afc80)
效果如图2-18所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_111.jpg?sign=1739289905-7UDrUimn6B0ErzWMhBYWAgd4hYAo4wdo-0-b9de558ce94cbbf195d8379f4ad3c06f)
图2-18
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_112.jpg?sign=1739289905-uN9gc187wGrM7Kc5GtOvXSbvoAqWKLTf-0-5f3bbce025c9dba9ee9615d4e912ad1c)
扫码查看彩色图
可以看出,由于Matrix操作的是坐标轴,所以在Y轴方向上倾斜45°时,所画矩形已经不是正常的矩形了,这是因为Matrix改变的是坐标轴方向上的倾斜角度。
下面再尝试一下matrix.preSkew(1,0,200,200);:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_113.jpg?sign=1739289905-r0uvb5myqLN7Y9kXQRR1q5lGLCCAo30q-0-f06b9551be224afffba69f2a79b4cba0)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_114.jpg?sign=1739289905-OSzrDzHfPu5Ax8R97STXmFf0lH6V96zD-0-1c9686ddd345a4da6dd1a8237fb0b0dd)
这里什么都没有改变,只是单纯地使用了Skew相关函数有错切中心点的声明方式,错切中心点为(200,200),效果如图2-19所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_115.jpg?sign=1739289905-4g42npxEdj2xQaoXZguRJqyVYai7eqzG-0-91f1c4e5fabbd529273b02e4f7885b1a)
图2-19
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_116.jpg?sign=1739289905-rZqyQzWZJFtfT0YOZbAUK0nTd99CJe0J-0-9eec52055d682a7505433ea926c320ea)
扫码查看彩色图
乍一看可能有点困惑,图2-20展示了以上完整的实现过程。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_117.jpg?sign=1739289905-rNePWvovDjVB3wV88AALn5LGmBnqIby1-0-23f06a0c8c5699f87169bdc9e011f585)
图2-20
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_118.jpg?sign=1739289905-RxwBmaXMrazekorWYKZzpbJm72xWUXQP-0-66ac879de58317b11c2a159f49c4d0b3)
扫码查看彩色图
在第4步中,回移至点(-200,-200)可能会让读者产生疑问,下面我将这一步进行分解,如图2-21所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_119.jpg?sign=1739289905-ovfZLdxstU73JFNF7uqNXXBo3NwZwdqv-0-0038af1fd20d0dd61aee64f76a9ff8ec)
图2-21
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_120.jpg?sign=1739289905-2rPMC2HqoN92n42RL1EUruhbL0lYnzeJ-0-0a579f06c843d6ffc2a9ddae778e70c6)
扫码查看彩色图
2.2.5 其他功能函数之setSinCos
setSinCos函数主要用于旋转操作,但它的函数声明比较特殊,如下所示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_121.jpg?sign=1739289905-5Se2ndQYCqbCbg2ur8ePakuRg1wy7skU-0-264cf5fa9402988edb932850d6197725)
●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=1739289905-yJ7902fVvxbWwwUir73to73KcRaZr0vq-0-7feb8e017789e6aecda00cd2bf902271)
在这里,我们就不重复讲解了,大家可以实际操作一下,然后利用画图解析的方式来复现一下它的操作步骤。
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=1739289905-ns9CSS0ocUY7oykdUQrZffFfLBQZGLvV-0-261f996051cb51245e807d19406daf04)
这个矩阵形成的原理如下:假设有一个点P,其相对坐标系原点顺时针旋转后的情形如图2-22所示,同时假定点P离坐标系原点的距离为r。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_124.jpg?sign=1739289905-gy9kOZ86INUlyIF1lq08Pd6pDMZg8QLg-0-221d566c3a70194c26535ca4a2e59db0)
图2-22
假设在未旋转前,点P所在的位置为(x0,y0),而点P离坐标系原点的距离为r,所以用r计算出来的(x0,y0)如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_125.jpg?sign=1739289905-NzJpLyT5mpnsRBLpJKPsxss85Q66MVzj-0-270586d8fba1907ee2287cc8e26c54d7)
假设在点P旋转θ角度后,其新坐标用(x,y)表示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_126.jpg?sign=1739289905-uuszwsg1ozZQXVVxaxfAjjBBboxksrHO-0-2adf4fdf2917361a184a3aabbe5fcfb2)
转换为矩阵表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_127.jpg?sign=1739289905-fMShykWItIZmZi71FcZ3TpEHTyVe4jCS-0-5a0bdcc249d1a1c18687a23930384c1c)
所以,setSinCos函数只是一种旋转方式。一般情况下,不怎么使用这个函数,而使用Matrix的Rotate相关函数。
2.2.5.2 setSinCos函数的用法
下面演示一下setSinCos函数的用法,将示例代码改为:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_128.jpg?sign=1739289905-vvWsCuZPVC2KUG8EqKccSg4fA7zQgtil-0-949b12e680b5b26f1fd3f9a299c82f95)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_129.jpg?sign=1739289905-pIH5jJbJrNZ4aqnNnssHDpwyTMZ1qNQI-0-74e957a2ac06870fa536fa2c85015196)
代码长了好多,下面逐步进行讲解。首先,第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=1739289905-4fX3FK1mH6xzkoDeFBmALRaU44WaOZ4E-0-981fa104968b139bcce8665d9b4700eb)
图2-23
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_131.jpg?sign=1739289905-Z1uRLWQ1CSRhozA3lXQFX8OJbDyUDekR-0-837d95179845fc666818e27e03b16aa7)
扫码查看彩色图
到这里,大概了解了Matrix中一些函数的用法,但Matrix中的函数不止这些,后面我们将继续讲解Matrix中其他函数的用法。