在为关键帧设置动画时,我似乎忽略了这一点。我查看了很多代码示例,包括在MoveMe
文档中引用的Apple CAKeyframeAnimation
,但是,我找不到会导致我看到的差异。
我创建了一个CGMutablePathRef
,然后创建了一个CAKeyframeAnimation
并将其设置为沿路径设置图像视图的动画。创建一个动画组,这样我就可以在完成后删除视图。
然而,我的动画从未出现过。直到我旋转设备。看起来视图的重新布局导致动画启动。我尝试了明显的[theImageView setNeedsDisplay]
甚至setNeedsLayout
,以及容器视图。然而,在我需要的时候仍然无法让它工作。它们仅在我旋转设备时显示。
在下文中,-cgPathFromArray:
采用NSArray
个内部操作码转换为CGPathRef
。它被验证是正确的,因为当我旋转设备时,动画确实沿着编程的路径显示。
- (void) animateImage: (NSString*) imageName
onPath: (NSArray*) path
withDuration: (NSString*) duration
{
if (self.sceneView)
{
CGMutablePathRef animationPath = [self cgPathFromArray: path];
if (animationPath)
{
UIImage* image = [self findImage: imageName];
if (image)
{
UIImageView* imageView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, image.size.width, image.size.height)];
if (imageView)
{
CAKeyframeAnimation* keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath: @"position"];
imageView.image = image;
[self.sceneView addSubview: imageView];
keyFrameAnimation.removedOnCompletion = YES;
keyFrameAnimation.fillMode = kCAFillModeForwards;
keyFrameAnimation.duration = duration.floatValue;
keyFrameAnimation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear];
keyFrameAnimation.repeatCount = 0;
keyFrameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[keyFrameAnimation setPath: animationPath];
//group animation with termination block to cleanup
CAAnimationGroup* group = [CAAnimationGroup animation];
group.duration = keyFrameAnimation.duration;
group.removedOnCompletion = YES;
group.fillMode = kCAFillModeForwards;
group.animations = @[keyFrameAnimation];
CorpsAnimationCompletionBlock theBlock = ^void(void)
{
[imageView removeFromSuperview];
};
[group setValue: theBlock
forKey: kCorpsAnimationCompletionBlock];
group.delegate = self;
[imageView.layer addAnimation: group
forKey: nil];
}
}
}
}
}
任何人都可以帮忙解决这个问题吗?
答案 0 :(得分:1)
您可能遇到了麻烦,因为您要在同一事务中将图层添加到可见图层树中的图层中添加动画。 Core Animation不喜欢将动画附加到尚未提交的图层。您可以在添加图层后执行[CATransaction flush]
来解决此问题。
由于嵌套过多,您的代码很难看。考虑使用早期回报以使其更具可读性。
此外,您明确创建了-[UIImage initWithImage:]
初始化程序为您创建的相同框架。
如果你正在使用动画组并设置一个委托,那么你可以在动画结束时执行一个块,这是一种更简单的方法。您可以开始CATransaction
,设置事务的完成块,然后添加动画,然后提交事务。
因此:
- (void) animateImage:(NSString *)imageName onPath: (NSArray *)path
withDuration: (NSString *)duration
{
if (!self.sceneView)
return;
CGMutablePathRef animationPath = [self cgPathFromArray:path];
if (!animationPath)
return;
UIImage *image = [self findImage:imageName];
if (!image)
return;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self.sceneView addSubview: imageView];
// commit the implicit transaction so we can add an animation to imageView.
[CATransaction flush];
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
[imageView removeFromSuperview];
}];
CAKeyframeAnimation *animation = [CAKeyframeAnimation
animationWithKeyPath:@"position"];
animation.duration = duration.floatValue;
animation.timingFunction = [CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionLinear];
animation.path = animationPath;
[imageView.layer addAnimation:animation forKey:animation.keyPath];
} [CATransaction commit];
}