![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=1738994249-FahEqzChg8MlyJSgIZpHQAmpET1ahHGV-0-471b4536255d65003c11cfc0f5256ea4)
第一个构造函数经常使用,用于直接创建一个单位矩阵:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_21.jpg?sign=1738994249-ZCve30olPsAEQaYdP14fg3UHbCbDz96P-0-82dc68753bce142f21de78e577433850)
第二个构造函数则会利用一个已有的Matrix对象,复制出一个新的Matrix对象,其内部数据内容与已有的Matrix对象完全相同。
2.2.1.2 reset
reset函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_22.jpg?sign=1738994249-vNSDi2N1zyQ9FM7Sk7QzsCgDCIglVbWq-0-0aabb364d41a669be8eb5f94f2558767)
该函数用于重置矩阵,重置的矩阵为单位矩阵。
2.2.1.3 setTranslate
setTranslate函数的声明如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_23.jpg?sign=1738994249-qTTrbv70c8vjF4qJeQC7xn6Xg1BMh9Tn-0-a3327f0a76a2aadb07f2b8aa87e6636f)
该函数用于设置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=1738994249-TfIEUHGOhW1ghcNU6trpuHZOXeX17UmH-0-b53121d96474c97f81531376947b5b29)
效果如图2-1所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_25.jpg?sign=1738994249-fzDdqpp7LOfLLHpvkzx6IehB0Ghas9Uk-0-df9526ea1ea3827356623b36fc39b7f2)
图2-1
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_26.jpg?sign=1738994249-Bem06Gsch1wsUu1LEfJ7zGpEutUvQQkf-0-acd6cc918ebf207860814c66b6c93eb4)
扫码查看动态效果图
修改代码,改为沿Y轴平移:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_27.jpg?sign=1738994249-ZgrZh7Gd2MbShF5tQmzbGUJnN2LkPQhz-0-0e13794a6ed50ea4ba44f0263e20241f)
效果如图2-2所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_28.jpg?sign=1738994249-3mihpeD0FybCKIXgLLFMQLxmF1Dr4IFD-0-409244f27afeb2f2c5f8a7b9610149e0)
图2-2
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_29.jpg?sign=1738994249-UEyJwMOsKqFXEZqfxNqEhJXupO0y5d2V-0-5b040f21fae972dcd34688a53314c13f)
扫码查看动态效果图
我们回顾一下在使用Camera实现Y轴平移时的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_30.jpg?sign=1738994249-6unb0KHWNXb9lOUfs7dCUHqivRqvG92A-0-cd7c4d1c0a4ca504e9881bc5c0800394)
对应的效果如图2-3所示。
很明显,通过Camera和Matrix实现的沿Y轴平移的效果完全相反。下面来看看2D坐标系和3D坐标系的区别,如图2-4所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_31.jpg?sign=1738994249-t9L7XAzXMQaOgsSqwo5U8pgFWvamw5ql-0-e5c326e8591832216aedf5176fd6770e)
图2-3
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_32.jpg?sign=1738994249-kL0akDcsFOqGfGGzLUj6jKPekG9RB7oE-0-0c31f254f8b82d82da1ed96d9904915e)
扫码查看动态效果图
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_33.jpg?sign=1738994249-ui08Z3ALKRg9XOz9MBBOnMRqFAzkw7To-0-32850213e36c7dc8c601b6fab2d572cf)
图2-4
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_34.jpg?sign=1738994249-JZxsUcf6h3wbqko5XvJ9Iys2czvyH783-0-cef2c5afd1b2e3deaa0436191f8e6dde)
扫码查看彩色图
很明显,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=1738994249-QQnC6vaMUrUzMcqJQ9ItpYiqjG5cWEV1-0-338722c5a5b583445ef84f773021cf85)
该函数主要用于设置旋转角度,参数具体含义如下。
●float degrees:旋转角度。
●float px:旋转中心点的X坐标。
●float py:旋转中心点的Y坐标。
在第2个声明形式中是没有旋转中心点的,默认会围绕控件左上角原点进行旋转,比如下面的示例代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_36.jpg?sign=1738994249-XcdSO666WACHnhWasi3oeMxo0AGaB62y-0-41558ecf219366ed57a5ee3b80a0cf6c)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_37.jpg?sign=1738994249-FiCT69PUzwHJm82KzFbN0c4Nb1C5mv5a-0-94782977c1a9c96bb58e503e19e1efd0)
效果如图2-5所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_38.jpg?sign=1738994249-nZw78m1dF5ntX492V3P5g940AHmEVFnR-0-d90ea276949619e879e8704224fedf0f)
图2-5
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_39.jpg?sign=1738994249-xsWo4GdgnGdL3DTnyTbAaqWRq3Hsl4OS-0-63443c12d0336801148da50ebd963d4f)
扫码查看动态效果图
可见,使用matrix.setRotate(mProgress)实现的旋转操作,是以左上角为原点来进行旋转的。
假如,我们将旋转代码进行变换,以(50,50)为旋转中心点:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_40.jpg?sign=1738994249-NFBIoRAxe6wT7eCDUrS7HgkCtL6Iz17L-0-7cec432e0dee3fdb07bec1004361ebd7)
效果如图2-6所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_41.jpg?sign=1738994249-spkBSUbJ6wjsCtzPBGUR3ZxZlcLbuhqN-0-e62e14c7963bd34a2a175e5cec33e41f)
图2-6
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_42.jpg?sign=1738994249-zuZSZhnOiyfjLymQwTRUfKMkxPPNQflb-0-ae6f018aef8cb52f96e697c58cb88cbc)
扫码查看动态效果图
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=1738994249-8JAc8iyVP9Uot9lo0EXvh2WTgE9Mi7jb-0-5bd34ab3c577f15f5db997027eb13da9)
旋转相关的函数有:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_44.jpg?sign=1738994249-owYLqI2xZLFGQ3hWXQ3VEcL8UcoZF73T-0-425891deb63692bf7aae38554c269731)
另外,还有其他操作方法,虽然此处没有提及,但凡是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=1738994249-xdIYmZpn5MVbutIidBrkyOu0fqMCKnrt-0-5c1a8e70129a798005c8687ad9d4d1a0)
在上面的公式中,Translate操作对应的矩阵的缩写为T,很明显,前乘的操作方式是原矩阵在乘号前面。
同样地,如果我们在原矩阵上使用matrix.postTranslate(10,15),那么矩阵的乘法次序如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_46.jpg?sign=1738994249-qjoyXPt4taVhFRVG1L39jHKSi4mLic3z-0-60be5172b41acddde912dd39bea6619b)
很明显,原矩阵在乘号的后面。
区分前乘和后乘的主要原因是,矩阵乘法不满足交换率。
再增加一点难度,如下面的伪代码,其中同时运用了多个pre和post运算,这时的运算顺序是什么样的呢?
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_47.jpg?sign=1738994249-IHZS8n0yimQ3MF6GP3PLiEDZpFZ5QtpG-0-70710460ebdd54bdea77987005dc6fc5)
假设Translate操作对应的矩阵为T,同样地,Rotate操作对应的矩阵为R。
下面逐步分析这段代码对应的矩阵操作顺序。首先是第1步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_48.jpg?sign=1738994249-p4rL5DD6M7sPJ3WvkIBQ43RCUGldZJD6-0-4a5a9466c0eb970ea7efc8c43c1c9e83)
这一步创建了一个单位矩阵,假设该矩阵为M,此时的结果=M,其中
表示该步的结果矩阵。
然后是第2步的代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_51.jpg?sign=1738994249-GAgNX0L19ELjpa6A0JvmcTpA3aADGLa5-0-93f377eff5730d312b881808b5a9f2ef)
在原结果矩阵上前乘一个Translate操作,假设该Translate操作对应的矩阵为T1,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_52.jpg?sign=1738994249-nh5VK9LKwDe9LC4NFXhV9qwGSYjh8DEj-0-b3d8c255c4ea609f90b9b8c1b4c981f7)
其中是第2步代码执行完成后的结果矩阵。很明显,它等于当前的结果矩阵
前乘T1矩阵。
接着是第3步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_55.jpg?sign=1738994249-w1oWJ59B8IVnLB9o3XFjzYI1pwxtKx1h-0-dcb3dc3a1e0dffe601d1204563a7c2b0)
同样地,是在当前的结果矩阵的基础上前乘Rotate操作,假设该Rotate操作对应的矩阵是R,整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_57.jpg?sign=1738994249-ZMgtfD9rH55mrZ8KDGGP0cEbJjdWhJgj-0-95b64297ff19dac2d00082e9e362ddb6)
是第3步代码执行完成后的结果矩阵。
最后是第4步代码:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_59.jpg?sign=1738994249-9xdkytiwayV14D1JLMBETfjzYlwKRxzX-0-fc58fac17f5c9af94604b27f1fa15307)
表示在当前结果矩阵的基础上后乘一个Translate操作,假设该Translate操作对应的矩阵是T2,那么整个运算过程如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_61.jpg?sign=1738994249-9IH2oioaJzRk33fyHoGBpYzCdCpdpN95-0-4dc94bb812ad0a06d9771838b466fd11)
是第4步代码执行后的结果矩阵。可知,
是整段代码执行后得到的最终矩阵。
上述换算过程演示了矩阵的前后乘关系,以及如何通过公式表示整个过程,这个过程在后期代码中非常重要,很多时候,我们需要知道如何将想法转换成公式,最终通过代码将公式写出来。
2.2.2.2 更改旋转中心点
在第1章中,我们经常会在所有操作结束之后,将操作的中心点移到图像的中心点,即通过如下代码来实现,下面就来讲解代码的实现原理:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_64.jpg?sign=1738994249-JYG56zz6XzdrxC952sguXfU0A25MOZaS-0-6c8a8b219abd11d9c189d0c5e1ae928a)
首先,针对各种操作,有两条基本定理需要知晓。
(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=1738994249-tTIFa4VNR2iyWUXABDrmha9Gok0Nn8Xn-0-55c69a1d027441b2b72fddc1ce46af75)
所以,如果对该代码进行扩展,改为任何操作改变坐标系原点的通用情况的话,矩阵乘法公式变为:
M'=M×T××-T=T××-T
其原理也很简单,先通过平移操作将原点位置移到指定位置,然后对图像进行各种操作,操作完成后,再把原点位置移回去。
相应的代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_66.jpg?sign=1738994249-zNBw3q6zqjjvMBTtbtx8bKF0dJLxIt9I-0-c787d4a43f0548aa1ede7ff9a7361a80)
上面的代码逻辑非常简单,就是从前往后,每执行一个操作都使用一个pre函数,这样写虽然逻辑简单,但两个调整坐标系原点的平移函数——preTranslate函数,一个在整个代码段的最前面,一个却在整个代码段的最后面,就公式而言不好记忆,所以通常采用这种写法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_67.jpg?sign=1738994249-QJpIZ2ckoAzf4uNsx9HD9KGI99KlFofj-0-c0d7e75d07df791245a100e4c81b47a9)
即先做各种操作,然后使用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=1738994249-C6UBWmcB1z1ZQbORpZMZEL20cxfiNxdI-0-715392fb55252bbeb011c7cb897b3232)
可以看到,函数名中除了有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=1738994249-VS2v3F54YRUHaJ1JXKqYzjS0OUg2LhU4-0-21f5c019feb46855b93677bfc502d27e)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_70.jpg?sign=1738994249-Zh4aL6Ne3r65GWO85Oj0UKQAkDBox9l7-0-df302094632fd9686b8f1b5193d582cc)
在使用testScaleView时(activity_test_scale.xml)进行全屏展示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_71.jpg?sign=1738994249-y9h4hbWJC96x8qdFCSn1O7TfxaklcS6Q-0-3f9c951944623061a5b68c58659ed460)
效果如图2-7所示。
根据如图2-7所示的效果图,我们来重新看看在onDraw中具体执行了哪些操作。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_72.jpg?sign=1738994249-BkS6voknrrvdRPlxKiWkjCWlN4J3a5BT-0-dfe9c865f8d0d406fbfb3ab70892b117)
图2-7
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_73.jpg?sign=1738994249-Nb0ZTZnLs36BNpbdfrxFGzwg5pO1ySaq-0-be1177c17a0fbbb69372e68aa36d9ba2)
扫码查看彩色图
1.移动坐标系原点位置
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_74.jpg?sign=1738994249-wH8cqWzjB04Gkt6fmYv9NWL9yKIiJFFh-0-079bb2d163e7d38e0bcd2941ce561f33)
因为testScaleView是全屏显示的,默认的坐标系原点位于View的左上角。为了方便理解,先将View的坐标系原点移到整个View的中心点位置。
2.绘制矩形
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_75.jpg?sign=1738994249-cHKyM6bS3amtHf3cQLhpp7othzszzXo4-0-efc80caeb1ae2577103f91e5205283c8)
根据最新的坐标系位置,绘制出矩形区域,如图2-8所示,图中标上了坐标系,方便读者理解。
此时画出来的是RectF(0,400,400,0)这个矩形,即黑色方框。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_76.jpg?sign=1738994249-qAqn9WSnDPo1MtFBygkQK7BDswdoAVPE-0-acde503ff7bd912e5c5b539c089678db)
图2-8
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_77.jpg?sign=1738994249-6tT0h17aG4HvOXuqCQ3uXqA6c4OrHgLm-0-e1069e9a5401597f6e290875fc57b4e0)
扫码查看彩色图
3.缩小标尺
相关代码如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_78.jpg?sign=1738994249-J8Bt8qVWjUIcJ0hVtSgyw9d58g4izduf-0-76ab604e032b816346b8fb43913a4c65)
需要注意的是,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=1738994249-HdruJBjG368DH1TvPjYJO1H3pW6Nv3ye-0-3d8d83d67853003ff80253df971b745b)
图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=1738994249-oMxw1o4iYo0Y8NQuwuJtq6bgHzViwbsz-0-ef3aab7a67dfa0d38436e680718d7804)
此时,所画的矩形就是在缩小密度后的标尺上绘制的,绘制的矩形就是效果图中的红色矩形框。
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=1738994249-vB79TYG2I48FTxSjZ9YLQCuywXyafqos-0-47c846acfb456b672f17ffca41bcfd9a)
这里其实只改了一句代码: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=1738994249-DDsXRraOJaH4ckY3w7BOWX9evmF79LGf-0-3bb4ab2de29fa77bcaae5ddfcf598656)
图2-10
左图表示正常情况下的X轴与Y轴的正方向,右图表示X轴翻转后的X轴和Y轴的正方向。
在这种情况下的效果如图2-11所示。
效果图不难理解,黑框位置没变,红框在X轴上进行了翻转,这就是取负值时的效果。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_83.jpg?sign=1738994249-M4DX3LBuk16HsbywuIoP19CFnMyKXCtK-0-912bfb12144666df306fdb4a95b0e5ac)
图2-11
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_84.jpg?sign=1738994249-lCLulF13lTaTrNhWMMm3S06J21la01EP-0-03853b4182250604fc4410e64aa6bfc6)
扫码查看彩色图
2.2.3.3 缩放中心点的作用
从各个函数的声明可以看到,除了sx、sy外,还有px、py两个值,比如:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_85.jpg?sign=1738994249-wiPjchQDe4FjDnNKFLWs8nKdZSMZHaRl-0-e33c3b9d5daeae12dd26dc9f2f3c2b47)
从前面的内容可以知道,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=1738994249-6zxnVbEfsoNSiGlBNFI1iID1jXGuo735-0-d4ccc7569ab52638fc0cf56d9165530a)
如果深入Canvas的scale函数的源码中,就可以看到它的具体实现:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_87.jpg?sign=1738994249-RCZoAZNN6tAFT7VXRWRLmTNq7Dbr4rET-0-54fd47d67bf092d2c044aa4a3dfe254e)
其实这就是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=1738994249-iAkvkeVIG7uaeH9vraiuHlQuumbdPpzv-0-00a2c99e8725b82fa3e5507f565d4d80)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_89.jpg?sign=1738994249-8bIAETYXKEMk8kV5l6t1qafXeKe8tNw6-0-d31672845593ca3060dc7191e431f58c)
此时的效果图如图2-12所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_90.jpg?sign=1738994249-u0Poa7DYbCuyONcVy8xbVRwTfsmNSt9w-0-9f964c99c585ea11ae4eeb7fc3b4803f)
图2-12
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_91.jpg?sign=1738994249-FI6iARYQtpsSV3QTVdpVNUKuqfvMHrT9-0-7c79abf9b7d544d08309a108f54c6bb7)
扫码查看彩色图
它的完整变换过程如图2-13所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_92.jpg?sign=1738994249-jdFSDBnkXV7HVOihOnvrGqMMCNANFyc1-0-6b108bddc60a23390f798bd31bcdba7d)
图2-13
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_93.jpg?sign=1738994249-DG3seD808RNtyzHPVExw80KK3r7Ocbd8-0-793bc3090a2690a83b23d67afd1bc974)
扫码查看彩色图
从图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=1738994249-SGpc6n1INiMjxB4Xs6QLYEc7guDATNT0-0-e619b48d7323231f9b04c2d3a945f27e)
效果如图2-14所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_95.jpg?sign=1738994249-ngOuMk99VpFRgTDDcpGpOdQJKNiKg7xG-0-e21b32c0237ae4a26671e8c5099aa980)
图2-14
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_96.jpg?sign=1738994249-7oHRuEa6uMxTCZRtJV6QkVxjydPteOPS-0-982989832da91e94a22061cd64d30f58)
扫码查看彩色图
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=1738994249-lejU36dTw8o6VG25OJpeylmstviNB48H-0-33ffcd0216d0692d68cbb7607d3975e8)
图2-15
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_98.jpg?sign=1738994249-g0sXqOgSsj2D1yoMFa4gFS9S0p9ulOTV-0-9ca0effcbcafefab00c8bbf693ead8ef)
扫码查看彩色图
X轴错切时,是保持坐标系的Y轴不变,X轴的值做线性变换,表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_99.jpg?sign=1738994249-Nr8cVWfHzerPDck17J1X7chomczv8BtP-0-139ffb1932f84a5a192a758c8c2728b5)
可以看出,对应到每一个点上,y坐标都没变,而x坐标都向后推了ky0的距离。所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_100.jpg?sign=1738994249-cY1AtnaJ1VXsZv3NZDTSHKcvdMjdbt7T-0-5ecd90ac5744a432cbf5c4d770fccb04)
注意变量k所在的位置,前面我们讲解位置矩阵的各个标志位时,已经提过该位置的含义,其主要用于标识SKEW_X:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_101.jpg?sign=1738994249-bHBS9ivxqHEjIYm5lhtN2TaRZ0NBYM4Y-0-a633c5e92f8e7c5a738a821a7b1dd9ba)
需要非常注意的是,在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=1738994249-lo4iVB2wRKLEARvlFHscwlU9Pcf7GwnT-0-8fc5c82ddd698cca2b6d3e49fb42508f)
图2-16
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_103.jpg?sign=1738994249-XM2aAOzBM8xBd3gF6z6lggSWVc0aYwSO-0-14959ea41f0faea3b3e255cbe60266f4)
扫码查看彩色图
同样地,所对应的公式如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_104.jpg?sign=1738994249-LaBUP1HTZuZS7lw1ttkDcKwDGkSeyOwC-0-61093d35b171ed6050f13938e4368c96)
同理,在Y轴错切时,改变的是X轴方向上的斜率。
X轴、Y轴同时错切(如图2-17所示):
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_105.jpg?sign=1738994249-RpPTxfOVvLHL5L4bhBiI8pnEJvkeEoGh-0-4946d2643a5cd0fbfb4b7e1349f0c935)
图2-17
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_106.jpg?sign=1738994249-u3jQjf4NUOsqVbiQytAoT6see8fRgCx8-0-be3f58d6da43b4508a87ccbdc81775cf)
扫码查看彩色图
在X轴、Y轴同时错切时,表示在X轴和Y轴方向上同时倾斜一个角度,很明显,两个倾斜角度是完全独立、各不相关的。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_107.jpg?sign=1738994249-oIbmwb4YmE1RXHA9lp9AFSg1GWzfr8RZ-0-1cb09b027afc9972f8cc9b064bc4ae48)
m表示X轴方向上的错切值,n表示Y轴方向上的错切值。
2.2.4.2 错切的用法
在了解了公式之后,下面来看看Matrix中Skew相关函数的声明及使用方法:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_108.jpg?sign=1738994249-IZ0TalRi4L3FCW90d43vPES8sZYXott1-0-7fed42da0dfaab915cefeb11dadebdbc)
同样地,除了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=1738994249-wGNbcNpZw1smocopsicHVR7tgFLSenkz-0-08144126d95856cb225acf8665a65059)
同样需要注意的是,虽然第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=1738994249-gnCorqdcHkH4FDYA3rHaMqJtMEsTe2uH-0-72ec0e4ac631e2f4793d17381c8e6330)
效果如图2-18所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_111.jpg?sign=1738994249-nZOSU50AubtbFHMc34l8yAqxPtvlFeVM-0-d40c0b18a8e46fa81e7742b95c39b70f)
图2-18
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_112.jpg?sign=1738994249-OheSi6T2LiSzsUxfUBPrXke0a563RV4R-0-010283c62146b525517f985193e51d71)
扫码查看彩色图
可以看出,由于Matrix操作的是坐标轴,所以在Y轴方向上倾斜45°时,所画矩形已经不是正常的矩形了,这是因为Matrix改变的是坐标轴方向上的倾斜角度。
下面再尝试一下matrix.preSkew(1,0,200,200);:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_113.jpg?sign=1738994249-kr25Pm3FctHlVCN7R98hmqMYjyY3Etfi-0-8ad9e64d4282b29a9af0e54853b00457)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_114.jpg?sign=1738994249-OzKmTgfrlfFempn59lKgfUkw7IKiU1XJ-0-4e139724a6617820b5348ff2f58d23a4)
这里什么都没有改变,只是单纯地使用了Skew相关函数有错切中心点的声明方式,错切中心点为(200,200),效果如图2-19所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_115.jpg?sign=1738994249-ShgVLAY5JaY8xDUrpZP0gW4oNdrbLyTf-0-037c89508376a7bea14f93116438537d)
图2-19
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_116.jpg?sign=1738994249-D8aInogYicogjFL57HnZZgOHk6lzj0x9-0-d4f6daa1a5246e6234628d39518838b2)
扫码查看彩色图
乍一看可能有点困惑,图2-20展示了以上完整的实现过程。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_117.jpg?sign=1738994249-wsj17yrYWM7Xli4cvJRXxdjPknHSJbSI-0-610ee339b590c5b7b733e75c205474a7)
图2-20
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_118.jpg?sign=1738994249-xFvWqWzoAtYvmiXG1qD01vLt99IS86W1-0-f13e068796225aedd1750b1649fb748d)
扫码查看彩色图
在第4步中,回移至点(-200,-200)可能会让读者产生疑问,下面我将这一步进行分解,如图2-21所示。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_119.jpg?sign=1738994249-N7ByD6hQOwvSM4hktheRhGJXzcz7piDo-0-72d6f30ddb36b928344f0c89ee49268c)
图2-21
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_120.jpg?sign=1738994249-do0pv50NmyKxSQxg7XwonpKRU07FtOKn-0-b503c8fd04ba8a4da503869f809e8805)
扫码查看彩色图
2.2.5 其他功能函数之setSinCos
setSinCos函数主要用于旋转操作,但它的函数声明比较特殊,如下所示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_121.jpg?sign=1738994249-4PY8QL3YSBDVBkelpA9I2s8rYtlgN82w-0-5aa53e1916664c453ce5d4cd9c165ba2)
●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=1738994249-EjRqr4GAtUSwgrjkl2P0dRwJtu1t0Dlj-0-eae942f0329c69db7fa65b2c75c13739)
在这里,我们就不重复讲解了,大家可以实际操作一下,然后利用画图解析的方式来复现一下它的操作步骤。
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=1738994249-3WNtz3DI18kLDaltw8L09B3N5P1pGvBb-0-548f05fe8902c1d372540db5b13a8a6b)
这个矩阵形成的原理如下:假设有一个点P,其相对坐标系原点顺时针旋转后的情形如图2-22所示,同时假定点P离坐标系原点的距离为r。
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_124.jpg?sign=1738994249-emwqF5RmldCxqjJqgWMkquWWCD3xX0Rt-0-e17d009ab684d43ef358482b6444dde9)
图2-22
假设在未旋转前,点P所在的位置为(x0,y0),而点P离坐标系原点的距离为r,所以用r计算出来的(x0,y0)如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_125.jpg?sign=1738994249-nGLdJTxv21UE8w92qUOC32MRVBe0BPxk-0-6cb00166d513568ad46949f16db78aee)
假设在点P旋转θ角度后,其新坐标用(x,y)表示:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_126.jpg?sign=1738994249-nwFYmHmab71AngMjvBqkNmXFRUlVWU2I-0-f0cd38895f3002181733bae37c5838c1)
转换为矩阵表示如下:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_127.jpg?sign=1738994249-0z96I8CyVdtbau8tawejNIX57NHYSofE-0-b5cb52246a43db6c7085f8342af128a1)
所以,setSinCos函数只是一种旋转方式。一般情况下,不怎么使用这个函数,而使用Matrix的Rotate相关函数。
2.2.5.2 setSinCos函数的用法
下面演示一下setSinCos函数的用法,将示例代码改为:
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_128.jpg?sign=1738994249-hLJa1UuOG9IXZ1FDXEIOQs09OLDcX8R0-0-f0d7336a7354b97e41bfba36e0d4ba1b)
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_129.jpg?sign=1738994249-TzIpcD0M0bkzssf2P21PPm4SvYGrdrlE-0-6b297f2fa9c7a303862c8311a76066b1)
代码长了好多,下面逐步进行讲解。首先,第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=1738994249-YiHFWPnESDdTgx616lmg9v8wF4CzXmQ1-0-fbf68912a673af28e89633cbfa677fe1)
图2-23
![img](https://epubservercos.yuewen.com/0CBE40/19391577408683706/epubprivate/OEBPS/Images/txt002_131.jpg?sign=1738994249-79kxgcm9CZ3qPgM5FEqCdo0oYf1VQx6R-0-43ecff9077180852cf778d55f05d85dc)
扫码查看彩色图
到这里,大概了解了Matrix中一些函数的用法,但Matrix中的函数不止这些,后面我们将继续讲解Matrix中其他函数的用法。