Demo 地址
今天使用CGAffineTransform遇到一个问题,可能是坑,在这说明下:
CGAffineTransform 提供了3个Api给大家用:
移动:(A)
public func translatedBy(x tx:CGFloat, y ty:CGFloat) ->CGAffineTransform
缩放:(B)
public func scaledBy(x sx:CGFloat, y sy:CGFloat) ->CGAffineTransform
旋转: (C)
public func rotated(by angle:CGFloat) ->CGAffineTransform
swift Api提供了返回值CGAffineTransform,我们可以链式调用,很方便 view.A.B.C (A B C 代表上面的3个Api)
现在问题来了:
1. view.A.A.A.A.A.A 或 view.B.B.B.B.B 或 view.C.C.C.C.C.C 方式多次调用,移来移去,缩放缩放,转来转去嘛,很ok
2. view.A.B.C 或 view.B.A.C 或 view.C.A.B 效果会是一样的吗? 答案是NO
3. view.A.A.A.B.B.C 或 view.A.B.C.A.B.C
4. view.[A.A.A.B.B.C] 或 view.[A.B.C.A.B.C] 此种方式不采用链式调用,而是将每次的改变值都累加到一个总的值里,执行一个总值的transform,效果会和3一样吗? 答案是NO
具体效果可以看我的Demo里 trans3 trans4trans5 trans6 trans7 trans8
看几个例子:
1.
self.firstView.transform =self.firstView.transform.scaledBy(x:0.2, y: 0.2).translatedBy(x:100.0, y: 100.0)
self.firstView.transform = self.firstView.transform.translatedBy(x:100.0, y: 100.0).scaledBy(x:0.2, y: 0.2)
效果一样吗? 答案是NO,frame的大小是一致的,但是center是不一样的。
方式一: center:157.0,336.833333333333 -> center:177.0,356.833333333333 实际移动距离为 0.2*100 = 20
方式二:center:157.0,336.833333333333 -> center:257.0,436.833333333333 实际移动距离为100
有点意思:先缩后移的话,移动的距离被缩放了;先移后缩则没问题
2.
self.firstView.transform =self.firstView.transform.scaledBy(x:0.5, y: 0.5).translatedBy(x:100.0, y: 100.0).scaledBy(x:0.4, y: 0.4)
self.firstView.transform = self.firstView.transform.scaledBy(x:0.2, y: 0.2).translatedBy(x:100.0, y: 100.0)
效果会一样吗? 答案是NO,frame的大小是一致的,但是center是不一样的。
方式一:center:157.0,336.833333333333 -> center:207.0,386.833333333333 实际移动距离为 0.5*100 = 50
方式二:center:157.0,336.833333333333 -> center:177.0,356.833333333333 实际移动距离为 0.2*100 = 20
有点意思:结合实例1的方式二和实例2的方式一,看的出缩放不会对它前面的移动有改变,只会改变它之后的移动,那是仅对下一个移动起作用,还是对以后所有的移动都起作用呢? 我们来看实例3
3.
self.firstView.transform =self.firstView.transform.scaledBy(x:0.5, y: 0.5).translatedBy(x:100.0, y: 100.0).scaledBy(x:0.4, y:0.4).translatedBy(x:100.0, y: 100.0)
self.firstView.transform =self.firstView.transform.scaledBy(x:0.2, y: 0.2).translatedBy(x:200.0, y: 200.0)
效果会一样吗? 答案是NO,frame的大小是一致的,但是center是不一样的。
方式一:center:157.0,336.833333333333 -> center:227.0,406.833333333333 实际移动距离为 0.5*(100 + 0.4*100) = 70
方式一:center:157.0,336.833333333333 -> center:197.0,376.833333333333 实际移动距离为 0.2*200 = 40
OK,上面的问题有了答案:缩放会对它右侧所有的移动进行改变。
4.
self.firstView.transform =self.firstView.transform.scaledBy(x:0.5, y: 0.5).translatedBy(x:100.0, y: 100.0).scaledBy(x:0.4, y:0.4).translatedBy(x:100.0, y: 100.0).scaledBy(x:0.5, y: 0.5).translatedBy(x:100.0, y: 100.0)
self.firstView.transform =self.firstView.transform.scaledBy(x:0.1, y: 0.1).translatedBy(x:300.0, y: 300.0)
效果会一样吗? 答案是NO,frame的大小是一致的,但是center是不一样的。
方式一:center:157.0,336.833333333333 -> center:237.0,416.833333333333 实际移动距离为 0.5*(100 + 0.4* (100 + 0.5*100)) = 80
方式二:center:157.0,336.833333333333 -> center:187.0,366.833333333333 实际移动距离为 0.1*300 = 60
OK 进一步验证了实例3的结论。
此处可以得出一个公式:实际移动距离 = B* (A + B*(A + B*( ...)))
有了这个结论,你应该知道怎么来使用transform达到预期的效果了吧,不会被移的一头雾水了。。
我开始的预期是移动和缩放是相互独立的,都是以Frame的center进行的,不管是先移后缩,还是先缩后移,效果应该是一样的,结果呢,呵呵,被打脸了
先控制个笑脸在屏幕上游荡的话,还是自己累积变化量吧,否则都不知道会飘到哪去。。 具体看Demo里的 trans5
继续更新:
上面只涉及到移动和缩放功能,还没有涉及到旋转。接着看实例
5.
self.firstView.transform = self.firstView.transform.rotated(by: CGFloat(Float.pi/3)).translatedBy(x: 100.0, y: 100.0)
self.firstView.transform = self.firstView.transform.translatedBy(x: 100.0, y: 100.0).rotated(by: CGFloat(Float.pi/3))
效果会一样吗? 答案是NO,frame的大小是一致的,但是center是不一样的。
方式一:center:157.0,336.833333333333 -> center:120.397471925123,473.435877008508 实际移动距离为 f(Float.pi/3)*100 f的具体内容不再细究,有兴趣可以研究下
方式二:center:157.0,336.833333333333 -> center:257.0,436.833333333333 实际移动距离为 100
可以看得出来:先移后转没有影响,先旋转后平移的话,旋转会对后续的平移产生变化,应该也是对后续所有的平移起作用。
有意思的一个点:不管是方式一还是方式二,执行 2/(1/3) = 6次后,view就回到了原点,赚了一圈回来了。 6次是怎么算出来的呢?一圈是2*pi,每次旋转pi/3,所以是6次喽。平移的距离越大,转的圈就越大,从上面的公式也可以看的出来。
今天先到这吧