您的位置:首页 > 移动开发 > Swift

CGAffineTransform链式调用的问题

2017-07-13 17:25 155 查看
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 -> [/b]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次喽。平移的距离越大,转的圈就越大,从上面的公式也可以看的出来。

今天先到这吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息