第三部分 核心动画的层--第五章 层的变换

第三部分 核心动画的层--第五章 层的变换,第1张

概述第三部分 核心动画的层 第一部分 核心动画开篇 免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作! 著作权声明:本文由http://blog.csdn.net/mengtnt翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接。 第五 第三部分 核心动画的层 第一部分 核心动画开篇 免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作! 著作权声明:本文由http://blog.csdn.net/mengtnt翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接。
第五章 层的变换

到现在,我们已经讨论了如何在屏幕周围移动一些几何元素,改变颜色,和多种多样其他有趣的效果。在这一章中,我们将进一步讨论。转换器是一个容器,用来描述应用到层上的一些矩阵转换,从而达到一些惊奇的效果。

变换又是什么那?一个变换是一个术语,它包含了一些改变尺寸,位置或者沿着一个或者更多的面,旋转一个物体的功能。变换是被应用使用一个矩阵函数,幸运的是我们不需要关心这个矩阵函数。无论我们需要旋转或者缩放一个层,我们必须使用一个变换去完成这个渴望的效果。

矩阵变换这个话题可以涉及到一个很深的数学问题上,这个超越了我们本章的范围。相反,这一章触及了一些更加普通和有趣的变换,例如在3D空间旋转一个层,或者一个有趣的缩放效果,这些如何发生。

缩放变换

为了展示一些矩阵变化的效果,我们使用一个简单的层,然后进行一些变换。第一个变换是缩放一个层从一个尺寸到另一个。开始做这个例子,如清单5-1

[plain]  view plain copy - (voID)applicationDIDFinishLaunching:(NSNotification*)notification{   NSVIEw *contentVIEw = [[selfwindow] contentVIEw]; CALayer *layer = [CALayer layer];   CGcolorRef color;   color = CGcolorCreateGenericRGB(0.0f,0.0f, 0.0f, 1.0f); [layer setBackgroundcolor:color];   [contentVIEw setLayer:layer];[contentVIEw setWantsLayer:YES];   workLayer = [CALayer layer];   color =CGcolorCreateGenericRGB(0.5f, 0.5f, 1.0f); [workLayersetBackgroundcolor:color];   [workLayersetCornerRadius:5.0f];   color =CGcolorCreateGenericRGB(0.0f, 1.0f, 1.0f); [workLayersetbordercolor:color];   [workLayersetborderWIDth:2.0f];   CGRect workFrame = [layerbounds]; workFrame.origin.x = workFrame.size.wIDth / 4; workFrame.origin.y =workFrame.size.height / 4; workFrame.size.wIDth /= 2; workFrame.size.height /=2;   [workLayersetAnchorPoint:CGPointMake(0, 0)]; [workLayer setFrame:workFrame];   [layeraddSublayer:workLayer];   }  

                                   清单5-1

在-applicationDIDFinishLaunching:方法中,我们获得了contentVIEw的一个引用,设置了它的层和标志它作为层的背景。通过设置这个层,我们保证了那个视图背景使用了什么类型的层。

当contentVIEw是被安装好时,我们下一步就就是构造这个我们需要 *** 作的层。它的背景颜色设置为灰色,并且通过使用-setCornerRadius:设置角是圆形的。下面,把边框的颜色用2个像素设置为绿色的。最后,那个层的大小设定为contentVIEw的1/4,剧中显示。

在Interfacebuilder中,给窗口增加3个按钮;我们要演示的每个变换:缩放,旋转,和3D旋转。结果窗口显示如下


                               图5-1 窗口

scale按钮是关联到方法-scaletransform:,实现如下清单5-2

copy -(IBAction)scaletransform:(ID)sender {   NSValue *value = nil;CABasicAnimation *animation = nil; CAtransform3D transform;   [[self workLayer] removeAllAnimations];   animation = [CABasicAnimationanimationWithKeyPath:@”transform”]; transform = CAtransform3DMakeScale(0.5f,0.5f, 1.0f);   value = [NSValuevalueWithCAtransform3D:transform];   [animation setTovalue:value];   transform =CAtransform3DMakeScale(1.0f, 1.0f);   value = [NSValuevalueWithCAtransform3D:transform]; [animation setFromValue:value];   [animationsetautoreverses:YES]; [animation setDuration:1.0f]; [animationsetRepeatCount:100];   [workLayeraddAnimation:animation forKey:kScaleKey]; }                         清单 5-2 缩放转换

这个方法会移除所有已经存在的动画,如果用户点击了好几个按钮,那些存在的动画就会堆积起来。下一步,我们想构造一个动画对象,那可以指导层怎么去变换。为了做这些,构造一个CABasicAnimation使用变换路径,这将告诉动画它要改变transform这个属性,无论这个层是否被应用,然后开始应用矩阵的变换到动画中。你可以使用很多种方法构造矩阵变换。这里的方法,我们使用CAtransform3DMakeScale这个方法,需要传递x,y,z轴用来完成转换。就像列表5-2所示,我们设定CAtransform3DMakeScale的x,y分别为0.5,然后我们单独留下z轴。为了创建抖动效果,下一步就要设定CAtransform3DMakeScale为1.0。通过设定x和y为1.0,我们就可以触发放大恢复的效果。

当CAtransform3DMakeScale值被设定后,设定autoReverse为YES,给它设定一个1秒的慢的时间段,然后设定一个最大的重复数;这里我们使用100。最后,我们增加创建好的动画到层上面,通过使用关键字指派动画。我们要使用一个大一点重复数,以至于给于一个动画一直运行的假象。如果动画真的遍历到了100遍,那么就会停止。

使用旋转变换

下一个变换我们来旋转层。层就沿着一个轴旋转,然后就自动恢复这个旋转,如清单5-3所示

copy -(IBAction)rotatetransform:(ID)sender; {   NSValue *value = nil;   CABasicAnimation *animation =nil; CAtransform3D transform;   [[self workLayer]removeAllAnimations];   animation = [CABasicAnimationanimationWithKeyPath:@”transform”]; transform =CAtransform3DMakeRotation(1.57f, 1.0f); value = [NSValuevalueWithCAtransform3D:transform];   transform =CAtransform3DMakeRotation(0.0f,248); line-height:18px"> [animationsetFromValue:value];   [animationsetautoreverses:YES];   [animation setDuration:1.0f];   [animationsetRepeatCount:100];   [workLayeraddAnimation:animation forKey:kScaleKey];   }  

          清单5-3 旋转转换

在这个例子中,CAtransform3DMakeRotation被应用沿着一个轴在层上旋转。不像清单5-2所展示的那样,这个例子用了4个参数:第一个参数是角度,用弧度表示,和下面三个数字是x,y和z轴。层是在x轴上被旋转1.57个弧度(那是90度)。x,z这些值有些不寻常。这个值涉及到了旋转的向量值,这些值在-1.0和1.0之间。旋转是被设置成全正的沿z轴,那就会产生一个顺时针的2D旋转。

使用3D旋转

下面的例子,比先前的例子更进一步了,使用了2个轴的旋转;看清单5-4

copy -(IBAction)rotate3Dtransform:(ID)sender; {   [[self workLayer]removeAllAnimations];   animation = [CABasicAnimationanimationWithKeyPath:@”transform”]; transform = CAtransform3DMakeRotation(1.57f,1.0f, 0.0f); value = [NSValue valueWithCAtransform3D:transform];   [animation setTovalue:value];   transform =CAtransform3DMakeRotation(0.0f, 0.0f); value = [NSValuevalueWithCAtransform3D:transform];   [animation setFromValue:value];   [animationsetautoreverses:YES];   [animation setDuration:1.0f];   [animationsetRepeatCount:100];   [workLayeraddAnimation:animation forKey:kScaleKey];                   清单5-4

清单5-4的方法和清单5-4的方法接近,除了CAtransform3DMakeRotation这个方法传递的值不一样。这个例子设置x和y轴为1.0,这会产生一个旋转,这种旋转会给你一种沿着两个轴的对角线滑过的幻觉。

因为我们旋转层90度并且自动恢复,这个例子貌似是沿着2个轴滑动。这是有用的,当你有一个两面的层(如一个图标或者一个戳),这样就让你在两面可以翻转。

锚点

关于层中先前已经提到过这个概念,在用变换时,锚点非常的重要。当你要给一个层应用一个变换时,变换会使用锚点来决定那一点来旋转,缩放等等。

到目前为止某些例子,缩放的变换(在清单5-2中展示的)会引起层在窗口的中间抖动,就像图5-2所示的那样。这是因为任何层默认的锚点都是在中间。

然而,如果我们改变-applicationDIDFinishLaunching:并且移动锚点到左下角,就像列表5-5所示的那样,我们就可以得到一个信服的结果。


                                       图 5-2 锚点在中间

copy CGRect workFrame = [layerbounds]; workFrame.origin.x = workFrame.size.wIDth / 4; workFrame.origin.y =workFrame.size.height / 4; workFrame.size.wIDth /= 2; workFrame.size.height /=2;   [layeraddSublayer:workLayer];  

                   清单 5-5 升级锚点

在清单5-5中,我们增加了一行代码[worklayer setAnchorPoint:CGPointMake(0,0)];这将重新定位锚点到层的左下角。当缩放的变换运行时,你可以看到层好像在左下角抖动,就像图5-3所示的那样。

通过锚点和变换的联合控制,你可以生产一些有趣的结果。例如,我们想要在一个固定的角落中,让一个层沿着z轴旋转。通过移动锚点到渴望的角落,这里旋转仅仅沿着z轴,那么这个层旋转就像是粘在一个东西上面一样。假如我们放置另一个层在同样的角落,这将有一个难以置信的效果。


                                   图5-3 左下角的锚点

联合变换

到目前为止,我们所涉及的都是单一的变换,要么旋转要么缩放层。但是如果你想要同时执行多个变换怎么办?幸运的是我们将会展示给你。

为了演示怎么来联合变换,我们建立了一个不同的工程。我们开始一个标准的cocoa应用程序从xcode模板中,然后增加一个appDelegate。那个appDelegate会获得一个NSWinDWo的引用计数,以便于可以控制它。然后,在-applicationDIDfinishLauching:这个方法中,我们安装到层上,展示如清单5-6.

copy CGcolorRef color;   NSVIEw *contentVIEw = [[selfwindow] contentVIEw]; CALayer *rootLayer = [CALayer layer];   color =CGcolorCreateGenericRGB(0.0, 0.0, 1.0); [rootLayersetBackgroundcolor:color];   [contentVIEw setLayer:rootLayer];[contentVIEw setWantsLayer:YES];   layer = [CALayer layer];   [layersetBackgroundcolor:color]; [layer setCornerRadius:5.0f];   [layer setborderWIDth:2.0f];   [layersetBounds:CGRectMake(0, 0, 100, 100)]; [layer setposition:CGPointMake(55, 55)];   [rootLayeraddSublayer:layer]; }  

                         清单 5-6联合转换

-applicationDIDFinishLaunching:方法获得了contentVIEw的一个引用,然后在开启这个层的后面增加一个CALayer给它。rootLayer的背景颜色也是黑的。

下一步,创建我们准备 *** 控的那个层,并且设置它的颜色为灰绿色,2像素的边框和5像素的圆角率。不像清单5-1,这个层会是100x100像素和位置在contentVIEw的左下角。

在interfaceBuilder中有另一个改变。增加一个方块按钮NSbutton给contentVIEw,设置为透明,并且调整大小和窗口一样。这就使用户无论点击窗口的那一点,都可以出发我们下面要做的行动。

绑定这个大按钮的行动给appDelegate,然后它的-(IBAction)action:(ID)sender这个方法就是我们下面要声明的。

当用户点击窗口时,我们想要workingLayer移动到右上角。伴随这个,我们也要旋转层180度平且缩放到原来尺寸的1/10。在清单5-7就是这个问题的解决方法。

copy -(IBAction)action:(ID)sender; {   NSRect frame = [[[selfwindow] contentVIEw] frame]; float x = frame.origin.x + frame.size.wIDth - 30;float y = frame.origin.y + frame.size.height - 30; CAtransform3D rotate;   [CATransaction begin];   [CATransactionsetValue:[NSNumber numberWithfloat:5.0f]   forKey:kCATransactionAnimationDuration];   [layersetposition:CGPointMake(x, y)];   scale =CAtransform3DMakeScale(0.1f, 0.1f,248); line-height:18px"> rotate =CAtransform3DMakeRotation(1.57f, 1.0f); [layersettransform:rotate];   [layer settransform:scale];   [CATransaction commit]; }  

               清单5-7 行动

然而,当代码运行时,这个层移动和旋转,但是它不能缩放。这是因为调用-settransform:这个方法仅仅能设置一个属性,之后最后设置的那个值将替换先前设置的值。尽管在一些情况下,这看起来是有用的。即使老的变换的移除和新的变换的设置也是2个动画,但是它没有影响我们例子中看到的效果。

因为变换覆盖了彼此,变换需要在应用到层上时,被联合起来。这个可以用CAtransform3DConcat方法,这将用2个CAtransform3D的引用,然后返回一个联合的CAtransform3D,例如清单5-8.

copy CAtransform3D scale;CAtransform3D combine;   [CATransaction begin];   [CATransaction setValue:[NSNumbernumberWithfloat:5.0f]   forKey:kCATransactionAnimationDuration];   [layersetposition:CGPointMake(x, y)];   scale =CAtransform3DMakeScale(0.1f,108); List-style:decimal-leading-zero outsIDe; color:inherit; line-height:18px"> rotate =CAtransform3DMakeRotation(1.57f, 1.0f); combine =CAtransform3DConcat(rotate, scale);   [layer settransform:combine];   [CATransaction commit]; }  
                                  清单5-8

在这个完整的-action:方法中,CALayer最后应该留下来的位置在开始CATransaction块开始之前就计算好了。这确保了改变动画在同一期间执行。我们给CATransaction设定执行时间段,通过使用+setValue:forKey:这个方法,传递一个kCATransactionAnimationDuration这个关键字。

在CATransaction已经开始之后,我们可以在层上设定我们想要的动画属性,然后它就使用CATransaction的执行时间自动的执行动画。代替构造若干个CABasicAnimation对象然后应用到层中,你可以直接设定属性。

第一个设定的属性就是位置。因为锚点就在层的中间,你能容易的计算出这个位置离窗口的右上角5个像素的位置,然后设定这个位置属性给层。

下一步,你需要构造变换来应用到这个层中。开始,先构造2个子变换,例如:

  创建一个缩放变换,缩放层到原来尺寸的1/10。

  构造一个旋转变换,旋转层1.57个弧度。

在这里带着这两个变换,下一步就是使用CAtransform3DConcat方法来联合它们。

当这两个变换是被联合时,应用它们到层上,然后提交CATransaction。结果就是那个层会优雅的从左下角移到右上角,缩放成原来尺寸的1/10并且移动时旋转180度。这给你的印象就像是随着层滑动到指定的位置,从无到有的缩放。

缩放vs边框

在联合变换的例子中,我们联合了缩放和旋转变换以达到渴望的效果。你可能说:为什么不仅仅用改变层的边框来替代,以避免联合变换的麻烦?

原因是在缩放层和改变它的边框之间有着非常重要的不同之处。当一个层缩放时,任然会认为层是一个原始的尺寸,并且在缩放被应用之前绘制原始的尺寸。然而,如果我们改变了尺寸,然后缩放层,层就看起来就不对了,因为它知道自己是一个不同的尺寸了。

例如,如果我们改变层的边框,在联合变换的例子中代替做一个层的变换,动画的结果将看起来如图5-4.


                                  图5-4 边框和缩放的动画

注意到最后层好像是一个圈。这是因为我们改变了层的边框,但是没有改变层的圆角率和边框的宽度。然而,当缩放变换是被使用时,结果就是我们看到的那样,如图5-5.这会是一个正方形。当你在看图5-5时,你会发现一个特点边框不可见。这是因为缩放后的边框比0.5个像素要小。同样,因为圆角(原始是5个像素)比1个像素要少,它也不再可见。当用一个复杂的层树工作时,改变边框和缩放的不同之处就富有戏剧性了。如果我们在放大这个层到100%,那么边框就将成为50个像素宽了。


                          图5-5 缩放和旋转的动画

总结

当你第一次使用变换进行工作时,会令人生畏。更糟糕的是,如果你决定在互联网上搜索时,它会使你更加的迷惑。这里过了一遍概念希望能帮助你意识到变换的有用和便捷之处。

总结

以上是内存溢出为你收集整理的第三部分 核心动画的层--第五章 层的变换全部内容,希望文章能够帮你解决第三部分 核心动画的层--第五章 层的变换所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1053815.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存