首页 > 代码库 > Core Animation 再次浅析
Core Animation 再次浅析
图层的内容动画
Core Animation提供的基础设施让轻松创建复杂图层动画变得异常简单,Core Animation扩展了所有拥有图层的视图。例如改变图层框架矩形的尺寸,改变其在屏幕上的位置,应用旋转变换,改变它的透明度。使用Core Animation初始化一个动画和改变属性一样简单,但你也可以显式的创建一个动画并设置动画的参数。
用简单的动画表现图层属性的变化
你可以以显式或隐式的执行简单的动画。隐式动画使用默认的定时器和动画属性展现动画。而显式动画需要你为动画对象配置一些参数。所以当默认的定时器能够很好的为你服务并且你所要的动画效果不需要太多代码时,隐式动画则非常的适合你。
简单的动画包括改变一个图层的属性,以及随着时间的推移,让Core Animation以动画的形式展现这些属性的变化。图层定义了许多会影响图层可视外观的属性。改变这些属性是以动画方式展现外观变化的一种方式。例如将图层的透明度从1.0修改为0.0,这将引起图层的淡出特效,最后图层变为透明。
重要:虽然你可以使用Core Animation接口直接让支持图层的视图产生动画,但这样做经常需要额外的步骤。
为了触发隐式动画,你所要做的是更新图层对象的属性。当更改的目标是图层树中的图层对象,更改将立即反映到对象上。而图层对象的可视外观并不会立即发生变化,Core Animation将图层对象属性的变化当做是一个触发器,用以创建和安排一个或多个可执行的隐式动画。如清单3-1那样修改图层对象属性,将引起Core Animation为你创建动画对象,动画对象将被安排在下一次更新周期运行。
清单3-1 隐式动画的方式呈现图层属性的变化
theLayer.opacity = 0.0;
为了显式地使用动画对象呈现相同的变化,创建一个CABasicAnimation对象并配置该对象的动画参数。在添加动画到图层之前,你可以设置动画的开始值与结束值,改变持续时间,或任何其他动画参数。你指定你想要动画的属性的键路径,接着设置动画参数。为了执行一个动画,你使用addAnimation:forKey:方法将动画对象添加到你想要展现动画的图层上。
清单3-2 显式动画的方式呈现图层属性的变化
CABasicAnimation* fadeAnimation = [CABasicAnimation animationWithKeyPath:@”opacity”; fadeAnimation.fromValue = http://www.mamicode.com/[NSNumber numberWithFloat:1.0];>
注意:创建一个显示动画,推荐是赋值一个值给动画对象的fromValue属性。如果你没有为该属性指定值,Core Animation将使用图层的当前值作为开始值。如果已经更新了属性作为它的最终值,这将致使fromValue属性值遭到干扰,结果可能并不是你想要的。
不同于隐式动画,隐式动画会更新图层对象的值。而显示动画不会更改图层树中的数据。显示动画仅是创建了一个动画。在动画结束之后,Core Animation从图层中移除该动画对象并使用当前的数据值重绘图层。如果你想让显示动画的改变成为永久性的,如你在之前的例子中看到的,你必须更新图层属性。
隐式和显示动画都会在当前运行循环周期结束之后开始执行,并且当前的线程必须拥有一个用于执行动画的运行循环runloop。如果你改变了图层的动画属性或者给图层添加了多个动画对象。所有这些动画将会同时被执行。例如将图层移动到屏幕之外的时候添加渐隐动画,这两个动画是同时运行的。然而你可以让动画对象在一个特殊的时间开始执行。
CATransition 和 CATransaction
过渡动画支持改变图层的可视性
按字面上理解,一个过渡动画对象为图层创建一个可动画的可视过渡。最普遍的过渡对象用法是动画一个图层的显现和消失。与基于属性的动画不同,一个过渡动画操纵一个图层的缓存图片以创建可视效果,如果通过单独的改变属性实现会非常的困难,也许根本无法实现。标准的过渡类型包括:将旧视图移开显示新视图、推入、移动、淡入淡出动画。在OS X上,你也可以使用Core Image过滤器创建使用其他特效类型,比如擦除、翻页、波纹、或你设计的自定义特效的过渡。
为了实现一个一个过渡动画,创建一个CATransition对象,然后添加该对象到包含过渡特效的图层上。你使用过渡对象指定所要执行的过渡类型以及过渡动画的开始点和结束点。你也可以不让过渡动画完整的执行。过渡对象让你指定动画运行的开始和结束进度值。这些值可以使动画在过渡的中间点开始或结束。
清单5-1用于在两个视图之间创建一个可动画的推入过渡。在例子中,myView1和myView2被放置在相同父视图中的相同位置,但只有myView1是当前可视的。推入过渡引起myView1一边渐隐一边向左滑出,直到它被隐藏,而myView2从右侧滑入变成可视。更新两个视图的隐藏属性确保两个视图的可视性在动画的结尾是正确的。对一个图层应用推入过渡,第一个滑出的图层的使用当前的可视性,而右侧滑入的图层使用最后修改后的可视性。
清单5-1 iOS中得两个视图间的过渡特效
CATransition* transition = [CATransition animation]; transition.startProgress = 0; transition.endProgress = 1.0; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromRight; transition.duration = 0.5; // 为两个图层加入过渡动画 [_myView1.layer addAnimation:transition forKey:@"transition"]; [_myView2.layer addAnimation:transition forKey:@"transition"]; // 最后,改变图层的可视性 _myView1.hidden = !_myView1.hidden; _myView2.hidden = !_myView2.hidden;
当两个图层包含相同的过渡特效,你可以对两个图层应用同一个过渡对象。使用相同的过渡对象也简化了代码。然而,你也可以使用不同的过渡对象并且如果对每个图层过渡参数都是不同的,那么就肯定需要使用两个不同的过渡对象。
清单5-2展示了在OS X平台上,如何使用Core Image过滤器实现一个过渡特效。配置带有你想要的参数的过滤器后,将过滤器赋值给过渡对象的filter属性,在完成这些之后,对动画的使用和其他类型的动画对象的使用是一样的。
清单5-2 在OS X平台,使用Core Image过滤器动画一个过渡特效
// Create the Core Image filter, setting several key parameters. CIFilter* aFilter = [CIFilter filterWithName:@"CIBarsSwipeTransition"]; [aFilter setValue:[NSNumber numberWithFloat:3.14] forKey:@"inputAngle"]; [aFilter setValue:[NSNumber numberWithFloat:30.0] forKey:@"inputWidth"]; [aFilter setValue:[NSNumber numberWithFloat:10.0] forKey:@"inputBarOffset"]; // Create the transition object CATransition* transition = [CATransition animation]; transition.startProgress = 0; transition.endProgress = 1.0; transition.filter = aFilter; transition.duration = 1.0; [self.imageView2 setHidden:NO]; [self.imageView.layer addAnimation:transition forKey:@"transition"]; [self.imageView2.layer addAnimation:transition forKey:@"transition"]; [self.imageView setHidden:YES];
注意:当在动画中使用Core Image过滤器时,配置过滤器是技巧性最强的地方。比方说,使用栏擦除过渡特效,指定一个输入角度,如果角度过大或过小可能导致没有过渡特效发生。如果你没有看到你期望的动画,尝试将你的过滤器参数调整为不同的值再运行查看。
显式事务可以改变动画的参数
对图层属性的每次更改都是事务的一部分。CATransaction类管理动画的创建和分组并在适当的时间执行动画。在大部分情况下,你不需要创建你自己的事务。无论什么时候,给图层添加显式或隐式动画,Core Animation会自动创建一个隐式事务。然而你也可以创建显式事务以能够更精确的管理动画。
使用CATransaction类提供的方法创建与管理事务。通过调用begin类方法,可以开始(或隐式地创建)一个新的事务;调用commit类方法可结束一个事务。两个方法之间的代码就是作为事务部分的变化。比如说,改变一个图层的两个属性,你可以使用清单5-5所示代码。
清单5-5 创建显式事务
[CATransaction begin]; theLayer.zPosition = 200.0; theLayer.opacity = 0.0; [CATransitoin commit];
使用事务的主要一个原因是显式事务的限制内,你可以改变动画的持续时间,定时函数以及其他参数。你也可以赋值一个完成块给整个事务,这样当动画组完成后能够得到一个通知。改变动画参数须要在事务字典中使用setValue:forKey:方法更改适当的键。比如说,为了改变默认的持续时间为10秒,则你需要改变kCATransactionAnimationDuration键,如清单5-6所示。
清单5-6 改变动画默认的持续时间
[CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:10.0f]; forKey:kCATransactionAnimationDuration]; [CATransaction commit];
在你想提供不同默认值给不同的动画集合的情况下你可以内嵌事务。为了一个事务中内嵌一个事务,仅需要再次调用begin类方法。每一个begin类方法必须有一个与之配对的commit类方法。仅在你提交了对最外层事务的变化之后,Core Animation开始相关的动画。
清单5-7显式了一个事务中嵌套另一个事务的例子,内层的事务改变与外层的事务相同的动画属性,但是使用不同的值。
清单5-7 内嵌显式事务
[CATransaction begin]; // Outer transaction // Change the animation duration to two seconds [CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration]; // Move the layer to a new position theLayer.position = CGPointMake(0.0,0.0); [CATransaction begin]; // Inner transaction // Change the animation duration to five seconds [CATransaction setValue:[NSNumber numberWithFloat:5.0f] forKey:kCATransactionAnimationDuration]; // Change the zPosition and opacity theLayer.zPosition=200.0; theLayer.opacity=0.0; [CATransaction commit]; // Inner transaction [CATransaction commit]; // Outer transaction