如何让CAAnimation在每个动画节目中调用块?

时间:2014-03-29 05:12:42

标签: ios objective-c core-animation

我可以以某种方式在每个" tick"上执行一个块。 CAAnimation?它可能像下面的代码一样工作。如果有一种方法可以使用选择器,那也可以。

NSString* keyPath = @"position.x";
CGFloat endValue = 100;

[CATransaction setDisableActions:YES];
[self.layer setValue:@(toVal) forKeyPath:keyPath];

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath];
animation.duration = 1;
animation.delegate = self;

__weak SelfClass* wself = self;
animation.eachTick = ^{
    NSLog(@"Current x value: %f", [wself valueForKeyPath:keypath]);
};

[self.layer addAnimation:animation forKey:nil];

2 个答案:

答案 0 :(得分:11)

典型的技术是使用显示链接(CADisplayLink)。

因此,为显示链接定义一个属性:

@property (nonatomic, strong) CADisplayLink *displayLink;

然后实现启动,停止和处理显示链接的方法:

- (void)startDisplayLink
{
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)stopDisplayLink
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
    CALayer *layer = self.animatedView.layer.presentationLayer;

    NSLog(@"%@", NSStringFromCGRect(layer.frame));
}

注意,虽然视图是动画,但您无法查看其基本属性(因为它将反映最终目的地而不是"在飞行中"位置),而是您可以访问动画视图&#39 ; s层presentationLayer,如上所示。

无论如何,在开始动画时启动显示链接。并在完成后将其删除。

使用标准的基于块的动画,您可以执行以下操作:

[UIView animateWithDuration:2.0 delay:0 options:0 animations:^{
    view.frame = someNewFrame;
} completion:^(BOOL finished) {
    [self stopDisplayLink];
}];

[self startDisplayLink];

使用Core Animation,它可能看起来像:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = [NSValue valueWithCGPoint:startPoint];
animation.toValue = [NSValue valueWithCGPoint:endPoint];

[CATransaction setAnimationDuration:1.0];
[CATransaction setCompletionBlock:^{
    [self stopDisplayLink];
}];

[CATransaction begin];
[self.animatedView.layer addAnimation:animation forKey:nil];
[CATransaction commit];

[self startDisplayLink];

答案 1 :(得分:0)

使用CADisplayLink实现这一目标是理想的,但直接使用它需要相当多的代码。

无论您是在Core Animation级别还是UIView动画级别工作,请查看开源INTUAnimationEngine library。它提供了一个非常简单的API,几乎与基于UIView块的API完全相同,但它每帧运行animations块,传递完成百分比:

// INTUAnimationEngine.h

// ...

+ (NSInteger)animateWithDuration:(NSTimeInterval)duration
                           delay:(NSTimeInterval)delay
                      animations:(void (^)(CGFloat percentage))animations
                      completion:(void (^)(BOOL finished))completion;

// ...

如果您只是在启动其他动画时同时调用此方法并使用相同的持续时间&延迟值,你将能够在动画的每一帧接收回调。如果您不喜欢复制代码,INTUAnimationEngine也可以专门用于运行您的动画,具有支持自定义缓动功能等高级功能。