Core Animation--4.高级动画技巧

高级动画技巧
 
有许多方式配置基于属性或关键帧的动画。如果需要同步和异步地执行多个动画,可以使用更高级的行为同步这些动画的定时或将它们链接在一起。你可以使用其他动画对象类型创建可视过渡,以及其他感兴趣的动画特效。
 
过渡动画支持改变图层的可视性
按字面上理解,一个过渡动画对象为图层创建一个可动画的可视过渡。最普遍的过渡对象用法是动画一个图层的显现和消失。与基于属性的动画不同,一个过渡动画操纵一个图层的缓存图片以创建可视效果,如果通过单独的改变属性实现会非常的困难,也许根本无法实现。标准的过渡类型包括:将旧视图移开显示新视图、推入、移动、淡入淡出动画。在OS X上,你也可以使用Core Image过滤器创建使用其他特效类型,比如擦除、翻页、波纹、或你设计的自定义特效的过渡。
 
为了实现一个一个过渡动画,创建一个CATransition对象,然后添加该对象到包含过渡特效的图层上。你使用过渡对象指定所要执行的过渡类型以及过渡动画的开始点和结束点。你也可以不让过渡动画完整的执行。过渡对象让你指定动画运行的开始和结束进度值。这些值可以使动画在过渡的中间点开始或结束。
 
清单5-1用于在两个视图之间创建一个可动画的推入过渡。在例子中,myView1和myView2被放置在相同父视图中的相同位置,但只有myView1是当前可视的。推入过渡引起myView1一边渐隐一边向左滑出,直到它被隐藏,而myView2从右侧滑入变成可视。更新两个视图的隐藏属性确保两个视图的可视性在动画的结尾是正确的。对一个图层应用推入过渡,第一个滑出的图层的使用当前的可视性,而右侧滑入的图层使用最后修改后的可视性。
 
清单5-1 iOS中得两个视图间的过渡特性
 
 
  1. CATransition* transition = [CATransition animation]; 
  2. transition.startProgress = 0; 
  3. transition.endProgress = 1.0; 
  4. transition.type = kCATransitionPush; 
  5. transition.subtype = kCATransitionFromRight; 
  6. transition.duration = 0.5; 
  7. // 为两个图层加入过渡动画 
  8. [_myView1.layer addAnimation:transition forKey:@"transition"]; 
  9. [_myView2.layer addAnimation:transition forKey:@"transition"]; 
  10. // 最后,改变图层的可视性 
  11. _myView1.hidden = !_myView1.hidden; 
  12. _myView2.hidden = !_myView2.hidden; 
当两个图层包含相同的过渡特效,你可以对两个图层应用同一个过渡对象。使用相同的过渡对象也简化了代码。然而,你也可以使用不同的过渡对象并且如果对每个图层过渡参数都是不同的,那么就肯定需要使用两个不同的过渡对象。
 
清单5-2展示了在OS X平台上,如何使用Core Image过滤器实现一个过渡特效。配置带有你想要的参数的过滤器后,将过滤器赋值给过渡对象的filter属性,在完成这些之后,对动画的使用和其他类型的动画对象的使用是一样的。
 
清单5-2 在OS X平台,使用Core Image过滤器动画一个过渡特效
 
 
 
  1. // Create the Core Image filter, setting several key parameters. 
  2.   CIFilter* aFilter = [CIFilter filterWithName:@"CIBarsSwipeTransition"]; 
  3.   [aFilter setValue:[NSNumber numberWithFloat:3.14] forKey:@"inputAngle"]; 
  4.   [aFilter setValue:[NSNumber numberWithFloat:30.0] forKey:@"inputWidth"]; 
  5.   [aFilter setValue:[NSNumber numberWithFloat:10.0] forKey:@"inputBarOffset"]; 
  6.   // Create the transition object 
  7.   CATransition* transition = [CATransition animation]; 
  8.   transition.startProgress = 0; 
  9.   transition.endProgress = 1.0; 
  10.   transition.filter = aFilter; 
  11.   transition.duration = 1.0; 
  12.   [self.imageView2 setHidden:NO]; 
  13.   [self.imageView.layer addAnimation:transition forKey:@"transition"]; 
  14.   [self.imageView2.layer addAnimation:transition forKey:@"transition"]; 
  15.   [self.imageView setHidden:YES]; 
 
 
注意:当在动画中使用Core Image过滤器时,配置过滤器是技巧性最强的地方。比方说,使用栏擦除过渡特效,指定一个输入角度,如果角度过大或过小可能导致没有过渡特效发生。如果你没有看到你期望的动画,尝试将你的过滤器参数调整为不同的值再运行查看。
 
自定义动画的定时
时间系统是动画的一个重要部分。通过Core Animation方法和CAMediaTiming协议可为动画指定精确的时间信息。共有两个Core Animation类适配该协议。其中之一是CAAnimation类,所以你可以在动画对象中指定时间信息。其二是CALayer,你可以为隐式动画配置一些与时间相关的功能。虽然隐式事务对象包装了这些动画,通常优先使用所提供的默认时间信息。
 
当考虑时间与动画的时候,理解图层对象如何与时间工作是重要的。每一个图层都有自己用于管理动画定时的本地时间系统。一般两个不同图层的本地时间系统足够的接近,你可以为每一个图层指定相同的时间值,用户不会察觉任何异样。然而,图层的本地时间系统可以被它的父图层或它自己的定时参数更改。比如说,改变图层的speed属性将引起图层或子图层上动画的持续时间成比例的变化。
 
为了帮助你确定一个图层的适当时间值,CALayer类定义了convertTime:fromLayer:以及convertTime:toLayer:方法。你可以使用这些方法转化一个固定的时间值到一个图层的本地时间系统,或者将某一图层的时间值转换为另一个图层的时间值。这些方法将媒体定时属性考虑进去,这可能影响图层的本地时间系统,返回值用于其他图层。清单5-3展示了一个例子,你应该常规地使用获取一个图层的当前本地时间系统。CACurrentMediaTime函数是一个便利函数,返回计算机的当前时钟时间,该方法用于获取并转换至图层的本地时间。
 
清单5-3 获取一个图层的当前本地时间
 
 
  1. CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil]; 
一旦你在图层的本地时间系统中有一个时间值,你可以使用该值更新与事件相关的动画对象或图层的属性。使用这些定时属性,你可以完成一些有趣的动画行为,包括:
 
Ø使用beginTime属性设置动画的开始时间。通常,动画开始于下一个更新循环周期。你可以使用beginTime参数延迟动画的开始几秒钟时间。该方式将链接在一起的两个动画设置某一个动画的开始时间为另一个动画的结束时间。

如果你延时了动画的开始。你可能也想设置fillMode属性为kCAFillModeBackwards。该填充模式将引起图层显示动画的开始值,即使在图层树中的图层对象包含了一个不同的值。没有填充模式,你将看到动画在开始执行前发生一次到结束值的跳跃。

Øautoreverses属性引起一个动画在指定的持续时间内执行并返回到动画的开始值。你可以将此属性与repeatCount属性联合使用,让动画在开始与结束值之间反复来回。对自动返回动画设置重复计数为一个整数(比如1.0)将引起动画停止在动画的开始值。添加一个半拍值(比如重复计数为1.5)将引起动画停止在它的结束值。
 
对动画组中的动画使用timeOffset属性,让动画一开始就出现在以后某时刻才会出现的状态。(Lets say you have an animation with a duration of 5 seconds. Normally your animation would run from time 0 to time 5. If you set a timeOffset of 2, your animation will start out at time 2, reach time 5 and then 'wrap around' and run time 0 to time 2.)
 
暂停与恢复动画
为了暂停一个动画,你可以利用图层适配CAMediaTiming协议这一点,设置图层动画的速度为0.0.设置速度为0暂停动画直到你改变该属性值为一个非零值。清单5-4展示了一个简单的关于如何暂停和恢复动画的例子。
 
清单5-4 暂停和恢复一个图层的动画
 
 
 
  1. -(void)pauseLayer:(CALayer*)layer { 
  2.   CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() 
  3.                                        fromLayer:nil]; 
  4.   layer.speed = 0.0; 
  5.   layer.timeOffset = pausedTime; 
  6.   
  7.   
  8. -(void)resumeLayer:(CALayer*)layer { 
  9.   CFTimeInterval pausedTime = [layer timeOffset]; 
  10.   layer.speed = 1.0; 
  11.   layer.timeOffset = 0.0; 
  12.   layer.beginTime = 0.0; 
  13.   CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() 
  14.                                            fromLayer:nil] - pausedTime; 
  15.   layer.beginTime = timeSincePause; 
 
 
显式事务可以改变动画的参数
对图层属性的每次更改都是事务的一部分。CATransaction类管理动画的创建和分组并在适当的时间执行动画。在大部分情况下,你不需要创建你自己的事务。无论什么时候,给图层添加显式或隐式动画,Core Animation会自动创建一个隐式事务。然而你也可以创建显式事务以能够更精确的管理动画。
 
使用CATransaction类提供的方法创建与管理事务。通过调用begin类方法,可以开始(或隐式地创建)一个新的事务;调用commit类方法可结束一个事务。两个方法之间的代码就是作为事务部分的变化。比如说,改变一个图层的两个属性,你可以使用清单5-5所示代码。
 
清单5-5 创建显式事务
 
 
 
  1. [CATransaction begin]; 
  2. theLayer.zPosition = 200.0; 
  3. theLayer.opacity = 0.0; 
  4. [CATransitoin commit]; 
 
使用事务的主要一个原因是显式事务的限制内,你可以改变动画的持续时间,定时函数以及其他参数。你也可以赋值一个完成块给整个事务,这样当动画组完成后能够得到一个通知。改变动画参数须要在事务字典中使用setValue:forKey:方法更改适当的键。比如说,为了改变默认的持续时间为10秒,则你需要改变kCATransactionAnimationDuration键,如清单5-6所示。
 
清单5-6 改变动画默认的持续时间
 
 
 
  1. [CATransaction begin]; 
  2. [CATransaction setValue:[NSNumber numberWithFloat:10.0f]; 
  3. forKey:kCATransactionAnimationDuration]; 
  4. [CATransaction commit]; 
 
 
在你想提供不同默认值给不同的动画集合的情况下你可以内嵌事务。为了一个事务中内嵌一个事务,仅需要再次调用begin类方法。每一个begin类方法必须有一个与之配对的commit类方法。仅在你提交了对最外层事务的变化之后,Core Animation开始相关的动画。
 
清单5-7显式了一个事务中嵌套另一个事务的例子,内层的事务改变与外层的事务相同的动画属性,但是使用不同的值。
 
清单5-7 内嵌显式事务
 
 
 
  1. [CATransaction begin]; // Outer transaction 
  2. // Change the animation duration to two seconds 
  3. [CATransaction setValue:[NSNumber numberWithFloat:2.0f] 
  4.                  forKey:kCATransactionAnimationDuration]; 
  5. // Move the layer to a new position 
  6. theLayer.position = CGPointMake(0.0,0.0); 
  7. [CATransaction begin]; // Inner transaction 
  8. // Change the animation duration to five seconds 
  9. [CATransaction setValue:[NSNumber numberWithFloat:5.0f] 
  10.                  forKey:kCATransactionAnimationDuration]; 
  11. // Change the zPosition and opacity 
  12. theLayer.zPosition=200.0; 
  13. theLayer.opacity=0.0; 
  14. [CATransaction commit]; // Inner transaction 
  15. [CATransaction commit]; // Outer transaction 
 
 
给动画添加透视
你可以在三维空间中操纵图层。当只对简单的Core Animation显示层使用一个平行投影,平行投影本质上是将场景扁平化到二维平面。该默认行为引起相同尺寸不同zPosition的图层显式的尺寸相同,即使是图层离z坐标很远。你一般在三维场景中会有一个透视的检视口。你可以通过更改图层的变换矩阵改变这个行为,让动画包含透视信息。
 
当更改一个场景的透视,你需要更改包含被观察的图层的父图层的sublayerTransform矩阵。更改父图层简化了你需要给所有子图层应用透视信息的代码。同时也保证了透视信息被正确的应用给不同平面互相覆盖的同胞子图层。
 
清单5-8显示了一种为父图层创建简单透视变换的方式。自定义eyePosition变量是沿着z坐标从观察点到视图图层相对距离。通常为eyePosition指定一个正数让图层按照预期的方式调整。eyePosition越大,结果则是一个更加扁平的场景,而值越小将引起图层间更加戏剧性的视觉表现。
 
清单5-8 为父图层添加一个透视变换
 
 
 
  1. CATransform3D perspective = CATransform3Didentity; 
  2. Perspective.m34 = -1.0 / eyePosition; 
  3. //为父图层应用变化 
  4. myParentLayer.sublayerTransform = perspective; 
 
给父图层配置的时候,你可以改变任何子图层的zPosition属性,然后基于这些子图层与视点的相对距离观察这些子图层尺寸的变化。
 
改变一个图层的默认行为
Core Animation使用动作对象为图层实现了隐式动画行为。动作对象服从CAAction协议并定义了一些运行于图层的相关行为。所有CAAnimation对象都实现了这个协议。无论何时,如果一个图层对象的属性发生变化,则这些动作对象将被分派执行。
 
可动画属性是其中一种动作类型,你可以定义几乎任何你想要的动作。然而你需要定义你的动作对象并关联到你的图层对象。
 
自定义适配CAAction协议的动作对象
为了创建你自己的动作对象,你需要适配CAAction协议并实现runActionForKey:object:arguments:方法。在该方法中利用可用的信息执行任何你想要在图层上的动作。你可能使用该方法给图层添加动画对象或者你可能使用该方法执行另外的任务。
 
当你定义了一个动作对象,你必须决定动作以何种方式被触发。动作的触发器定义了你用于注册动作的键。动作对象可在下面的情况下被触发:
Ø图层的某一个属性值被改变。这可以是图层的任何一个属性,不仅仅是可动画的属性。 (你也可以给添加到图层的自定义属性关联动作。)识别动作的键是属性名。
Ø 图层变成可视或被加入到图层层次中。则识别动作的键为kCAOnOrderIn。
Ø 图层从图层层次中被移除。则识别动作的键为kCAOnOrderOut。
Ø 图层是即将包含一个变换动画。则识别动作的键为kCATransition。
 
动作对象设置给图层才产生效果
在动作被执行之前,图层需要找到一个相应的动作对象。与图层相关的动作的键可以是被更改的属性名或一个特殊的识别动作的字符串。当一个适当的事件发生在图层上,图层调用它的actionForKey:方法搜索与键关联的动作对象。你的应用可以介入到搜索期间的几个关键点,并提供一个与键相关的动作对象。
 
Core Animation以下面的顺序搜索动作对象:
 
1.如果图层有一个代理,并且代理实现了actionForLayer:forKey:方法,图层调用该方法。代理必须完成下面所述操作之一:
l返回给定的键指定的动作对象
l 如果代理不处理动作则返回nil,而搜索操作将继续。
l 返回NSNull对象,这将引起搜索操作立即结束。
 
2. 图层在图层的action字典内搜索给定的键
 
3. 图层在style字典中查询一个包含键的动作字典。(换句话说,style字典包含一个actions键,它的值也是字典。图层在第二个字典中搜索给定的键。)
 
4. 图层调用它的defaultActionForKey:类方法。
 
5. 图层执行由Core Animation定义的隐式动作(如果有)。
 
如果你在任何一个适当的搜索点提供了一个动作对象,图层将停止它的搜索并执行返回的动作对象。当它找到了一个动作对象,图层调用对象的runActionForKey:object:arguments:方法执行动作。如果你为一个给定的键定义的动作是一个CAAnimation类实例,你可以使用默认的方法实现执行动画。如果你自己定义了服从CAAction协议的对象,你必须使用你的对象的方法实现做任何适当的动作。
 
设置动作对象的位置依赖于你打算如何更改图层。
 
对于只应用在指定环境的动作,或对于已经使用代理对象的图层,提供一个代理和实现它的actionForLayer:forKey:方法。
 
对于不使用代理的图层对象,添加动作到图层的actions字典。
 
与定义在图层对象上的自定义属性相关的动作,包括动作在图层的style字典。
 
对于那些是图层行为基础的动作,子类化图层并覆盖defaultActionForKey:方法。
 
清单6-1 显示了一个用于给定动作对象的代理方法实现。在这种情况下,代理搜索图层contents属性的改变并将新内容转换为使用一个变换动画的位置。
 
清单6-1 使用图层代理对象提供一个动作
 
 
 
  1. - (id<CAAction>)actionForLayer:(CALayer *)theLayer 
  2.                         forKey:(NSString *)theKey { 
  3.     CATransition *theAnimation=nil; 
  4.     if ([theKey isEqualToString:@"contents"]) { 
  5.         theAnimation = [[CATransition alloc] init]; 
  6.         theAnimation.duration = 1.0; 
  7.         theAnimation.timingFunction = [CAMediaTimingFunction 
  8. functionWithName:kCAMediaTimingFunctionEaseIn]; 
  9.         theAnimation.type = kCATransitionPush; 
  10.         theAnimation.subtype = kCATransitionFromRight; 
  11.   
  12.   
  13.     return theAnimation; 
 
 
使用CATransaction类临时禁用动作
你可以使用CATransaction类临时禁用图层的动作。当你改变了一个图层的属性,Core Animation通常会为动画属性的改变创建一个隐式事务对象。如果你不想以动画的形式展现变化,你可以通过创建一个显示事务并设置它的kCATransactionDisableActions属性为True禁用隐式动画。清单6-2的代码片段 显示了将指定的图层从图层数中移除时禁用动画。
 
清单6-2 临时禁用一个图层的动作
 
 
 
  1. [CATransaction begin]; 
  2.   [CATransaction setValue:(id) 
  3.                    forKey:kCATransactionDisableActions]; 
  4.   [aLayer removeFromSuperlayer]; 
  5. [CATransaction commit]; 
 
 
提升动画的性能
 
Core Animation是提升based-app动画帧率的最佳方式 ,但使用Core Animation并不保证性能一定会得到提升。特别是在OS X中,你仍必须选择最有效的方式使用Core Animation的行为。跟所有和性能相关的问题一样,随着时间的推移,你应该使用Instruments测量和追踪你的应用的性能性能正在提升而不是在退化。
 
常规的技巧和窍门
有很多种方法可以让你的层运行的更加有效率(因为层是核心动画的基础)。就像任何优化一样,你应该先在优化前审查下现在的代码让动画表现如何,这个是基准,然后才能对比出优化有没有效果,效率是不是更高了
 
尽可能使用不透明图层
设置opaque属性为YES可以让核心动画知道不需要给图层维持alpha通道,没有alpha通道意味着就不需要渲染这层的背景内容了,从而节省了渲染时间。然后这个属性主要是用于设置层或者以层为基础的视图的,也或者是用于核心动画创造的底层bitmap层的情况。如果把一张图像直接设置为层的contents属性,那么这个图像的alpha通道会被强制保留,无论你设不设定这个值。
 
将复杂路径拆分成简单路径
CAShapeLayer类根据你提供的路径来渲染到bitmap图像,在合成的时候渲染成内容。这么做的优点是层总是在最佳分辨率绘制路径,但是这个优点会消耗额外的渲染时间。如果这个路径太复杂,渲染的代价就会很高,并且如果这个路径的尺寸经常改变(这会导致重绘也经常发生),用于绘画的时间也会增加,这会成为一个阻止最佳表现性能的瓶颈
 
有一个办法去降低绘制形状层的时间,就是把复杂的形状分拆成简单的形状。用更简单的路径和多层用于CAShapeLayer对象,这比绘制一个大的复杂路径时间快得多。因为绘制操作发生在CPU,合成工作发生在GPU,当然这种优化也取决于你的内容。因此,优化前以现有效果为基准很重要。
 
显式为相同的图层设置contents属性
如果你在多个层对象上使用同一张图片,自己加载图像,把这个图像直接分派给这些层对象的contents属性。分配一个图像到contents属性可以预防分配用于内容储备的内存空间(UIView实际并不将自己绘制到屏幕上,而是先绘制到它的图层上,然后是图层显示在屏幕上,视图并不会频繁的重绘;相反,它的绘图结果会被缓存起来,而绘图的缓存版本(后备存储)将被用到适当的地方)。反而这个层用你提供的图像当做后备存储。当几个层用同样的图片,那么这些层就在共享一份内存而不是为自己再分配一个图片拷贝。
 
总是将图层的尺寸设置为整数值
为了最好的效果,应该将层对象的宽和高设置为整数值,虽然你使用浮点数的形式设定图层边界的宽高,图层的边界最终用于创建一个bitmap图片。指定整型值会的宽高会简化核心动画必要的创建和管理备份存储与其他图层信息的工作。
 
如果需要,可以使用异步的方式渲染图层
任何在代理方法drawLayer:inContext或视图的drawRect:方法中的绘制操作都默认是和主线程是同步的,在某种情况下,同步的绘制你的内容可能不会有最好的效果和表现。如果注意到动画执行的不好,可能就得试试drawsAsynchronously这个层的属性(iOS 6引入),让这些操作在后台线程中工作。如果你这么做了,得确定绘制代码是线程安全的,而且理所应当你应该在将异步绘图的代码置入你的产品代码之前总是测试异步绘图的性能。
 
当给图层添加一个阴影指定一个阴影路径
让核心动画自己决定阴影的形状是个大的开销且影响app的表现。相比让它自己决定,应该用shadowPath属性明确地指定一个阴影形状。当你这么干的时候,核心动画用这个形状去绘制和缓存阴影特效。对那些从不改变或者很少改变形状的层,这是一个很好的效果提升通过减少渲染数量。
 
图层样式属性动画
 
在渲染处理期间,Core Animaiton持有图层的不同属性,并按顺序渲染这些属性。该顺序决定了图层最终的呈现。本章将说明通过设置不同的图层属性完成渲染的结果。
 
注意:OS X和iOS中得图层样式属性是不同的,本章将有提及。
 
几何属性
一个图层的几何属性指定它相对于它的父图层被显示的方式。几何属性页指定了图层圆角的半径以及应用到图层和它的子层的变换。图A-1显示了示例图层的边界矩形。
图A-1 图层几何
 
下面列出的CALayer属性制定了一个图层的几何结构:
l   bounds
l    position
l   frame(根据bounds和position计算得出,该属性是不是一个可动画属性)
l   anchorPoint
l   cornerRadius
l   transform
l     zPosition
 
注意:cornerRadius属性仅在iOS 3.0及以上被支持。
 
背景属性
Core Animation首先会渲染图层的背景。你可以为背景指定一个颜色。在OS X中,你也可以指定一个应用到背景内容的Core Image过滤器。图A-2显示了2个示例图层的版本。在左边的图层设置了backgroundColor属性,而右边的没有设置背景颜色。但有一个边框和一个应用在图层backgroundFilters属性上的挤压变形滤镜。
图A-2 有背景颜色的图层
 
背景滤镜被应用到位于图层背后的内容上。该内容主要是由父图层的内容组成。你可能使用一个背景滤镜让前景图层内容突出;比如说,通过应用一个模糊滤镜。
 
下面的CALayer属性会影响图层的背景显示:
 
backgroundColor
 
backgroundFilters(iOS不支持此属性)
 
注意:在iOS中,backgroundFilters属性在CALayer类中是被暴露的,但复制到该属性的滤镜是被忽略的。
 
图层内容
如果图层有任何的内容,该内容将被渲染在背景颜色的上面。你可以通过直接设置一副位图提供图层内容,或使用一个代理指定内容,或是子类化图层并直接绘制内容。并且你可以使用许多不同的绘图技术(包括Quartz、OpernGL、Quartz合成器)提供内容。图A-3显示了一个示例图层,它的内容是通过直接设置一副位图。位图内容由一个右下角是一个机器人图标的大透明空间构成。
图A-3 图层显示一副位图图片
 
带有圆角半径的图层不会自动裁剪它们的内容;然而,设置图层的masksToBounds属性为YES将引起图层裁减掉圆角以外的内容。
 
下面的CALayer属性影响一个图层的内容的显示:
Ø contents
ØcontentsGravity
ØmasksToBounds
 
子图层的内容
图层可能包含一个或更多的孩子图层,孩子图层被称为子图层(sublayer)。子图层被递归地渲染并相对于父图层的边界矩形进行定位。另外,Core Animation应用父图层的sublayerTransform给每一个子图层,sublayerTransform相对于父图层的锚点。你可以使用子图层变换应用透视,应用于所有图层的其他效果也是一样的。图A-4显示了一个含有2个子图层的示例图层。左边的版本包含了背景颜色,右边的版本没有背景颜色。
图A-4 显示子层内容的图层
 
设置图层的masktSToBounds属性为YES将引起超出图层边界的任何子图层被裁减掉。
 
下面的CALayer属性将影响一个图层的子图层的显示:
l sublayers
lmasksToBounds
lsublayerTransform
 
边框属性
一个图层可以使用一个指定的颜色和宽显示一个可选的边框。边框按照图层的边界矩形,并会将圆角半径值考虑进去。图A-5显示了一个添加了边框的示例图层。
图A-5 显示边框属性内容的图层
下面的CALayer属性将影响图层边框的显示
lborderColor
lborderWidth
 
平台注意点:borderColor和borderWidth属性仅在iOS 3.0及以上得到支持
 
滤镜属性
在OS X平台,或许你可能为图层内容应用滤镜效果。使用自定义的合成滤镜指定图层的内容与它的底部图层内容的混合方法。图A-6显示了一个应用了Core Image的分色器滤镜图层。
图A-6 显示滤镜属性的图层
下面的CALayer属性指定一个图层内容的滤镜:
Øfilters
Ø compositingFilter

平台注意点:在iOS中,图层忽略任何你赋值给他的滤镜值
 
阴影属性
图层可以显示阴影效果,并且可以配置阴影的形状、透明度、偏移、模糊半径。如果你不指定一个自定义的阴影形状,阴影是在图层的部分基础上,阴影并不是完全透明的。图A-7显示了相同图层应用红色阴影的多种不同版本的结果。
 
左边和中间的版本包含一个背景颜色,所以阴影仅是显示在图层边框的周围。然而,右边的版本不包括背景颜色,在这种情况下,阴影将应用于图层的内容、边框以及子图层。
图A-7 显示阴影属性的图层
 
下面的CALayer属性影响图层阴影的显示:
lshadowColor
lshadowOffset
lshadowOpacity
lshadowRadius
lshaodwPath
 
平台注意点:shadowColor、shadowOffest、shadowOpacity和shadowRedius属性在iOS3.2+中才得到支持。shadowPath属性在iOS3.2及以上得到支持,OS X中10.7及以上得以支持。
 
不透明度属性
一个图层的不透明度属性决定了多少背景内容透过图层被显示。图A-8显示了一个示例图层,它的不透明度被设置为0.5。这将允许部分背景图片穿透显示出来。
图4-8 包含不透明度属性的图层
下面的CALyaer属性指定图层的不透明度:
l opacity
 
蒙版属性
你可以使用一个蒙版遮蔽所有或部分图层内容。蒙版本身是一个图层对象,它的alpha通道被用于决定被遮蔽的内容和被透射的内容。蒙版图层内容的不透明区域允许下方的图层内容穿透显示 而透明区域部分或完全地遮蔽了下方的内容(类似于PS里面的蒙版白的为显示区域,黑的为隐藏区域)。图A-9显示了由一个蒙版图层和两个不同的背景合成的示例图层。左边的版本,图层的透明度设置为1.0。右边的版本,涂层的透明度为0.5,导致穿透图层蒙版部分的背景内容数量减少。
图A-9 合成蒙版属性的图层
 
下面的CALayer属性用于指定一个图层的蒙版
lmask
 
平台注意:蒙版属性在iOS3.0及以上版本得以支持
 
可动画属性
 
大部分的CALayer与CIFilter的属性是可动画的。该附录列出了这些属性,以及默认使用的动画。
 
CALayer可动画属性
表B-1 列出了你可能考虑动画的CALayer类的属性。表中也列出了每一个属性的默认动画对象类型,默认的动画对象被创建以执行一个隐式动画。
 
表B-1 图层属性和它的默认动画
 
 


 
 
表B-2 列出了用于默认的基于属性的动画的动画属性
表B-2 默认隐式的基本动画
 
 
 
表B-3列出了默认基于过渡动画的动画对象的配置
表B-3 默认隐式过渡
 
 
 
CIFilter可动画属性
Core Animation添加下面的可动画属性到Core Image的CIFilter类中。这些属性仅在OS X中有效。
name
enabled
 
键值编码扩展
 
Core Animation扩展了NSKeyValueCoding协议,因为它与CAAnimation、CALayer有关。扩展包括为一些键添加了默认的值、扩展了包装转换,并加入了对CGPoint、CGRect、CGSize和CATransform3D类型的键路径支持。
 
键值编码适应的容器类
CAAnimation和CALayer是键值编码适应的容器类,容器类的意思是你可以为任意的键设置值。即使有些键在CALayer中没有声明,你仍然可以像下面一样设置值:
 
 
  1. [theLayer setValue:@50 forKey:@”someKey”]; 
你可以像检索其他键路径一样检索任意键的值。比如为了检索之前设置的someKey键的值,可以像下面代码一样操作:
 
 
  1. someKeyValue = [theLayer valueForKey:@”someKey”]; 
 
支持的默认值
依靠一个类为没有设置值的键提供一个默认值,Core Animation为键值编码加入了一层转换操作。CAAnimation和CALayer类支持这层转换,你可以使用defaultValueForKey:类方法。
 
为了为键提供默认值,创建一个待操作类的子类,并覆盖它的defaultValueForKey:方法。在该方法内你应该检测传入的键参数,并返回适当的值。清单C-1给出了一个defaultValueForKey:方法的实现,该方法是为一个图层对象的maskToBounds键提供默认的值。
 
清单C-1 defaultValueForKey:实现例子:
 
 
  1. + (id)defaultValueForKey:(NSString *)key 
  2.     if ([key isEqualToString:@"masksToBounds"]) 
  3.          return [NSNumber numberWithBool:YES]; 
  4.     return [super defaultValueForKey:key]; 
 
 
 
 
包装转换
当键的值的数据类型是一个标量或C语言的结构体,你必须在将值赋值到图层之前将值包装成对象。当访问这类类型的值的时候,你必须将检索到得对象使用正确的类的扩展,将对象解包为正确的值。表C-1列出了常用的C语言数据类型以及包装这些类型的Objective-C类。
表C-1 包装C语言数据类型的包装器类
 
键路径对结构体的支持
CAAnimation和CALayer类可以使用键路径访问已选择的结构体域。该功能让指定结构体的域变得非常方便。你也联合使用setValue:forKeyPath:和valueForKeyPath:方法设置和获取结构体的域。
 
CATransform3D键路径
可以使用键路径支持检索包含一个CATransform3D数据类型的属性的指定变换值。为了为一个图层的变换指定完整的键路径,你可使用字符串值transform或sublayerTransform,后面再跟上表C-2中其中一个域作为键路径。比如,为了指定一个围绕图层z轴的旋转因子,你可以指定一个transform.rotation.z的键路径。
 
表C-2 变换域的键路径
 
 
接下来的例子显示了如何使用setValue:forKeyPath方法更改一个图层。该例子设置x轴的平移因子为10点,图层将按指定的坐标轴方向平移给定的点数量。
 
 
  1. [myLayer setValue:[NSNumber numberWithFloat:10.0] forKeyPath:@”transform.translation.x”]; 
注意:使用键路径设置值与使用Objective-c属性设置并不完全一样。你不能使用属性符号设置变换值。你必须使用带有之前介绍的参数的setValue:forKeyPath:方法。
 
CGPoint键路径
如果给定的属性的值是CGPoint数据类型,你可以选择表C-3其中的一个域名追加给属性以获得值或设置值 。比如说,为了改变图层position属性的x域,你可以将键路径写成position.x。
表C-3 CGPoint数据结构
 
 
CGSize键路径
如果给定的属性值是一个CGSize数据类型,你可以选择表C-4中其中一个域名追加给属性以获得值或设置值。
表C-4 CGSize数据结构域
 
 
 
CGRect键路径
如果给定的属性是CGRect数据类型值,你可以选择表C-5中其中一个域名追加给属性以获取或设置值。比如,为了改变一个图层边界属性的宽度属性,你可以将键路径写成bounds.size.width。
表C-5 CGRect数据结构的域名
 
 
 完
如果喜欢此文,记得点击文章下方的推荐,以让更多的人有所收获。文章中如有错误或不当之处望不吝指出,谢谢!我的邮箱和微博: xdreamarshal@gmail.com, http://weibo.com/xdream86
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值