[译] Core Animation 编程指南 - 改变图层默认行为

378

本文首发地址

Core Animation 使用 action 对象实现图层的隐式动画行为。action 对象遵守 CAAction 协议,并定义一些在图层上执行的相关行为。所有的 CAAnimation 对象实现了该协议,并且这些对象通常被分配在图层属性改变时执行。

动画属性是 action 的一种类型,你也可以定义任何包含你想要的行为的 action 。但为了实现该目的,你必须定义自己的 action 对象,并将它们与你 app 的图层对象关联。

自定义的 Action 对象遵守 CAAction 协议

去创建你自己的 action 对象,使你的类遵守 CAAction 协议,并实现 runActionForKey:object:arguments: 方法。在该方法中,使用可用的信息去执行你想在图层上应用的 actions 。你可能使用该方法给图层添加一个动画对象,或执行其他的任务。

当你定义 action 对象时,你必须决定 action 怎样被触发。触发器为 action 定义键,后面你使用该键注册 action。Action 对象在下面的情况下会被触发:

  • 图层的属性值改变时,可以是图层的任意属性,不仅是可以动画的属性。(你也可以将你给图层添加的自定义属性与 action 关联。)识别 action 的键就是属性的名字。
  • 图层变为可见的或被添加到图层层级结构中。识别 action 的键是 kCAOnOrderIn
  • 图层从图层层级结构中被移除。识别 action 的键是 kCAOnOrderOut
  • 图层即将参与过渡动画。识别 action 的键是 kCATransition

Action 对象必须安装在图层上才能生效

在 action 可被执行之前,图层对象需要寻找响应的 action 对象去执行。图层相关的 actions 的键是被修改属性的名字,或可识别 action 的一个特别的字符串。当图层上发生合适的事件时,图层会调用 actionForKey: 方法去用于 action 对象关联的键去搜索 action 对象。在搜索过程中,你的 app 可以在几个点插入自己,并为该键提供相关的 action 对象。

Core Animation 通过下面的顺序查找 action 对象:

  1. 如果图层有 delegate,并且 delegate 实现了 actionForLayer:forKey: 方法,图层调用该方法。delegate 必须做下面的其中一个:

    1. 通过给的键返回 action 对象。
    2. 如果它没有处理 action,返回 nil。该情况下搜索继续。
    3. 返回 NSNull 对象,该情况下搜索立即结束。
  2. 图层在图层 actions 字典中查询给定的键。

  3. 图层在 style 字典中查询包含键的 actions 字典。(换言之,style 字典包含 actions 键,其值也是字典 。图层在第二个字典中,用给定的键去查询。)

  4. 图层调用 defaultActionForKey: 类方法。

  5. 图层执行由 Core Animation 定义的隐式 action (如果有的话)。

如果你在任意合适的搜索点提供了一个 action 对象,图层会停止搜索,并执行返回的 action 对象。它发现一个 action 对象时,图层调用对象的 runActionForKey:object:arguments: 方法去执行该 action。如果你对于给定的键定义的 action 已经是 CAAnimation 的实例,你可以使用默认的实现去执行动画。如果你定义你自己的自定义对象遵守了 CAAction 协议,你必须使用该方法的对象实现来采取任何适当的操作。

你在哪安装 action 对象取决于你想如何修改图层。

  • 对于只想应用某些具体情况的 action,或已经使用 delegate 对象的图层,提供 delegate 并实现它的 actionForLayer:forKey: 方法。
  • 对于通常不使用委托的图层对象,请将 action 添加到图层的 actions 字典中。
  • 对于与在图层对象上定义的自定义属性相关的 action ,请将该 action 包含在图层的 style 字典中。
  • 对于对图层行为至关重要的 action,对图层进行子类化,并重写 defaultActionForKey: 方法。

例 6-1 展示了使用提供的 action 对象的 delegate 方法的实现。在这种情况下,delegate 查找图层 contents 属性的改变,并且使用过渡动画将新内容交换到相应位置。

例 6-1 使用图层委托对象提供

- (id<CAAction>)actionForLayer:(CALayer *)theLayer
                        forKey:(NSString *)theKey {
    CATransition *theAnimation=nil;
 
    if ([theKey isEqualToString:@"contents"]) {
 
        theAnimation = [[CATransition alloc] init];
        theAnimation.duration = 1.0;
        theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        theAnimation.type = kCATransitionPush;
        theAnimation.subtype = kCATransitionFromRight;
    }
    return theAnimation;
}

使用 CATransaction 类将 Actions 暂时禁用

你可以使用 CATransaction 类暂时禁用图层的 actions 。你改变图层属性时, Core Animation 通常创建一个隐式事务对象去动画改变。如果你不想动画改变,你可以通过创建一个显式事务,并且将 kCATransactionDisableActions 属性设置为 true 来禁用隐式动画。例 6-2 展示了从图层树移除指定图层时,如果用代码禁用动画。

例 6-2 暂时禁用图层的 actions

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
                 forKey:kCATransactionDisableActions];
[aLayer removeFromSuperlayer];
[CATransaction commit];

关于使用事务对象管理动画行为的更多信息,请参见显示事务允许你改变动画参数