当前位置:主页 > 开发频道 > Mac开发 > Cocoa >

涉及动画的一些代码

时间: 2010-02-03 11:03 点击:

当你做一个软件的动画时,你会花费大量时间在控制动画的代码上。通常,视图控制器的代码会花费大量时间在检测动画各图层的完成情况上。动画多了以后,用这种方法就非常麻烦。
英文原文  http://weblog.bignerdranch.com/?p=215

当你做一个软件的动画时,你会花费大量时间在控制动画的代码上。通常,视图控制器的代码会花费大量时间在检测动画各图层的完成情况上。动画多了以后,用这种方法就非常麻烦。你必须为每个动画里的元素设置代号,并防止他们播放完了就消失。为此你不得不写一大堆重复的代码。

要是像控制UI那样控制动画该多简单,每个图层的动画完成时,都会触发此前预设的行为。这样,你就控制一段动画完成以后继续播放动画或执行代码。
怎么实现呢?看看“CALayer”子类,图层和动画间有很好的对应关系。下面是这个子类的代码:

BNRActionLayer.h:

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

@interface BNRActionLayer : CALayer {
NSMutableDictionary *targetActionPairs;
}
- (void)addTarget:(id)t action:(SEL)a forKey:(NSString *)k;
- (void)removeTarget:(id)t action:(SEL)a forKey:(NSString *)k;
- (NSArray *)actionsForTarget:(id)t forKey:(NSString *)k;
@end

BNRActionLayer.m:

#import "BNRActionLayer.h"

// Declare a private class to keep track of target-action pairs
@interface BNRActionLayerTargetActionPair : NSObject
{
id target;
SEL action;
}
@property (nonatomic, assign) id target;
@property (nonatomic, assign) SEL action;
@end

@implementation BNRActionLayerTargetActionPair
@synthesize target, action;
@end

@interface BNRActionLayer (Private)
- (NSMutableArray *)pairsForKey:(NSString *)k;
@end

@implementation BNRActionLayer
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
for(NSString *observedKey in targetActionPairs) {
if([self animationForKey:observedKey] == theAnimation) {
NSArray *pairs = [self pairsForKey:observedKey];
[self removeAnimationForKey:observedKey];
for(BNRActionLayerTargetActionPair *pair in pairs) {
if(flag)
[[pair target] performSelector:[pair action]
withObject:self];
}
}
}
}
- (void)addAnimation:(CAAnimation *)theAnimation forKey:(NSString *)key
{
NSArray *targetActionsForThisKey = [targetActionPairs objectForKey:key];
if([targetActionsForThisKey count] > 0) {
[theAnimation setRemovedOnCompletion:NO];
[theAnimation setDelegate:self];
}
[super addAnimation:theAnimation forKey:key];
}
- (void)addTarget:(id)t action:(SEL)a forKey:(NSString *)k
{
if(!targetActionPairs)
targetActionPairs = [[NSMutableDictionary alloc] init];

NSMutableArray *pairsForKey = [self pairsForKey:k];
if(!pairsForKey) {
pairsForKey = [NSMutableArray array];
[targetActionPairs setObject:pairsForKey forKey:k];
}

for(BNRActionLayerTargetActionPair *pair in pairsForKey) {
if([pair target] == t && [pair action] == a)
return;
}

BNRActionLayerTargetActionPair *newPair =
[[BNRActionLayerTargetActionPair alloc] init];
[newPair setTarget:t];
[newPair setAction:a];
[pairsForKey addObject:newPair];
[newPair release];
}
- (void)removeTarget:(id)t action:(SEL)a forKey:(NSString *)k
{
NSMutableArray *pairsForKey = [self pairsForKey:k];
if(!pairsForKey)
return;

BNRActionLayerTargetActionPair *removablePair = nil;
for(BNRActionLayerTargetActionPair *pair in pairsForKey) {
if([pair target] == t && [pair action] == a) {
removablePair = pair;
break;
}
}
[pairsForKey removeObject:removablePair];
}
- (NSMutableArray *)pairsForKey:(NSString *)k
{
return [targetActionPairs objectForKey:k];
}
- (NSArray *)actionsForTarget:(id)t forKey:(NSString *)k
{
NSMutableArray *list = [NSMutableArray array];
NSMutableArray *pairsForKey = [self pairsForKey:k];
for(BNRActionLayerTargetActionPair *pair in pairsForKey) {
if([pair target] == t)
[list addObject:NSStringFromSelector([pair action])];
}
return [NSArray arrayWithArray:list];
}
- (void)dealloc
{
[targetActionPairs release];
[super dealloc];
}
@end
怎么使用呢?确保图层使用的类型为BNRActionLayer

@implementation MyView
+ (Class)layerClass
{
return [BNRActionLayer class];
}
@end

当你创建 MyView 实例时, 可以为他添加目标行为.

- (void)applicationDidFinishLaunching:(UIApplication *)app
{
MyView *v = [[[MyView alloc] initWithFrame:someRect] autorelease];
[window addSubview:v];
[(BNRActionLayer *)[v layer] addTarget:self
action:@selector(viewDidFadeIn:)
forKey:@"Fade In"];

[window makeKeyAndVisible];

}
然后需要实现viewDidFadeIn,假设一种视角,使得这一切是可触的
- (void)viewDidFadeIn:(BNRActionLayer *)layer
{
// We can operate on the layer here, do some controllery stuff, and we
// can also get the this layers owning view. An implicit layer's delegate
// is always its view (on the iPhone).
MyView *v = [layer delegate];
[v setUserInteractionEnabled:YES];
}

那如何创建一个播放完成后能发送信息的动画呢?用同样的方法创建一个动画

- (void)activateView:(MyView *)v
{
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"opacity"];
[a setToValue:[NSNumber numberWithFloat:1]];
[a setDuration:1];

// The key here matches the key the target-action pair was added for
[[v layer] addAnimation:a forKey:@"Fade In"];
}

很酷吧,声明:我用了几天没发现问题。当然,这并不意味着代码是完美的,只是给您提个醒。

顶一下(3)

100%

踩一下(0)

0%

发表评论

评价: 中立 好评 差评 请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。

表情:

论坛新帖 进入论坛...