我终于为这个问题开发了一个解决方案。
本质上,我希望每一帧都能被回调并做我需要做的事情。
没有明显的方法来观察动画的进度,但实际上是可能的:
首先,我们需要创建一个新的 CALayer 子类,它有一个名为“progress”的可动画属性。
我们将图层添加到树中,然后创建一个动画,该动画将在动画持续时间内将进度值从 0 驱动到 1。
由于我们的进度属性可以进行动画处理,因此我们的子类上会为动画的每一帧调用drawInContext。这个函数不需要重绘任何东西,但是它可以用来调用委托函数:)
这是类接口:
@protocol TAProgressLayerProtocol <NSObject>
- (void)progressUpdatedTo:(CGFloat)progress;
@end
@interface TAProgressLayer : CALayer
@property CGFloat progress;
@property (weak) id<TAProgressLayerProtocol> delegate;
@end
以及实施:
@implementation TAProgressLayer
// We must copy across our custom properties since Core Animation makes a copy
// of the layer that it's animating.
- (id)initWithLayer:(id)layer
{
self = [super initWithLayer:layer];
if (self) {
TAProgressLayer *otherLayer = (TAProgressLayer *)layer;
self.progress = otherLayer.progress;
self.delegate = otherLayer.delegate;
}
return self;
}
// Override needsDisplayForKey so that we can define progress as being animatable.
+ (BOOL)needsDisplayForKey:(NSString*)key {
if ([key isEqualToString:@"progress"]) {
return YES;
} else {
return [super needsDisplayForKey:key];
}
}
// Call our callback
- (void)drawInContext:(CGContextRef)ctx
{
if (self.delegate)
{
[self.delegate progressUpdatedTo:self.progress];
}
}
@end
然后我们可以将图层添加到主图层中:
TAProgressLayer *progressLayer = [TAProgressLayer layer];
progressLayer.frame = CGRectMake(0, -1, 1, 1);
progressLayer.delegate = self;
[_sceneView.layer addSublayer:progressLayer];
并将其与其他动画一起设置动画:
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"progress"];
anim.duration = 4.0;
anim.beginTime = 0;
anim.fromValue = @0;
anim.toValue = @1;
anim.fillMode = kCAFillModeForwards;
anim.removedOnCompletion = NO;
[progressLayer addAnimation:anim forKey:@"progress"];
最后,随着动画的进行,委托将被回调:
- (void)progressUpdatedTo:(CGFloat)progress
{
// Do whatever you need to do...
}