使用核心动画在屏幕上移动 UIImage
Posted
技术标签:
【中文标题】使用核心动画在屏幕上移动 UIImage【英文标题】:Move UIImage across screen using core animation 【发布时间】:2013-02-11 23:38:37 【问题描述】:不要发布关于 UIView 动画的答案 我了解 UIView,我正在学习核心动画。我试图让图像向右移动 50 个单位,但我遇到了很多问题。首先,当动画被调用时,图像会跳到一个新的位置,运行,然后跳回原来的位置。我希望它简单地向右移动 50 个单位,停止,如果按下按钮,再次移动。我花了很多时间研究,我似乎无法找到问题所在。我的代码:
-(IBAction)preform:(id)sender
CGPoint point = CGPointMake(imView.frame.origin.x, imView.frame.origin.y);
imView.layer.position = point;
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
anim.fromValue = [NSValue valueWithCGPoint:point];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(point.x + 50, point.y)];
anim.duration = 1.5f;
anim.repeatCount =1;
anim.removedOnCompletion = YES;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[imView.layer addAnimation:anim forKey:@"position.x"];
imView.layer.position = point;
【问题讨论】:
【参考方案1】:我发现您的代码中有几个问题。
首先,您要像这样抓取帧原点:
CGPoint point = CGPointMake(imView.frame.origin.x, imView.frame.origin.y);
虽然这不是一个真正的问题,但您可以简单地这样做:
CGPoint point = imView.frame.origin;
问题在于您将图层的position
设置为其框架的原点。但默认情况下,位置控制视图的中心,框架的原点是它的左上角。您可能只想首先获取图层的位置:
CGPoint point = imView.layer.position; // equivalent to imView.center
其次,您正在使用 position.x
键路径,它需要 CGFloat
值,但您提供的是 CGPoint
值。这似乎不会在 ios 6.1 模拟器中引起问题,但假设它始终有效可能是个坏主意。
第三,您需要了解动画确实不会更改图层的属性!您通常操作的每个层(技术上称为 model 层)都有一个关联的 presentation 层。表示层的属性控制屏幕上的内容。当您更改模型层的属性时,Core Animation 通常会在表示层上自动设置一个动画(从旧值到新值)。这称为隐式动画。 UIView
抑制其层上的隐式动画。
当表示层上的动画结束并被移除时,表示层的属性将恢复为其模型层的值。因此,要使更改永久生效,您需要更新模型层的属性。通常最好先更新模型层的属性,然后添加动画,这样你的显式动画就会覆盖隐式动画(如果已创建的话)。
碰巧的是,虽然您可以为position.x
设置动画,但您需要在model
图层上设置position
以使其粘住。我对此进行了测试:
- (IBAction)perform:(id)sender
CGPoint point0 = imView.layer.position;
CGPoint point1 = point0.x + 50, point0.y ;
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
anim.fromValue = @(point0.x);
anim.toValue = @(point1.x);
anim.duration = 1.5f;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
// First we update the model layer's property.
imView.layer.position = point1;
// Now we attach the animation.
[imView.layer addAnimation:anim forKey:@"position.x"];
(请注意,我将我的方法称为perform:
。原帖中的方法似乎拼写错误。)
如果您想真正了解 Core Animation,我强烈建议您观看 WWDC 2011 的 Core Animation Essentials video。它长达一个小时,包含大量有用的信息。
【讨论】:
谢谢我看视频! @robmayoff 这在 swift 上不起作用。我不知道为什么。我在 swift 上重复了代码,但在返回起始位置时遇到了问题。我不明白。本文中的代码也不起作用(同样的问题):objc.io/issue-12/animations-explained.html#fnref3 但是,在不透明度的情况下正常工作。在动画停止后更新模型层的 opacity 属性,将保留 opacity 为您设置的值。 请发表您自己的问题并附上您的 Swift 代码。【参考方案2】:这是您让它工作所需要的。图层上的位置已设置,因此您可以将其用作fromValue
,只需修改它即可获得toValue
。另一个重要的步骤是将图层位置设置为endPos
,这样当动画结束时,图像视图将保持在正确的位置。
-(IBAction)preform:(id)sender
CGPoint startPos = imView.layer.position;
CGPoint endPos = CGPointMake(point.x + 50, point.y);
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
anim.fromValue = [NSValue valueWithCGPoint:startPos];
anim.toValue = [NSValue valueWithCGPoint:endPos];
anim.duration = 1.5f;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[imView.layer addAnimation:anim forKey:@"position.x"];
imView.layer.position = endPos;
【讨论】:
【参考方案3】:跳回是因为您在完成时移除动画
anim.removeOnCompletion = NO;
编辑#3:刚刚复制并尝试了您的代码,这是您所有问题的解决方案,几乎不言自明:
CGPoint point = imView.center;
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
anim.fromValue = [NSNumber numberWithFloat:point.x];
anim.toValue = [NSNumber numberWithFloat:point.x+50.0];//[NSValue valueWithCGPoint:CGPointMake(point.x + 50, point.y)];
anim.duration = 1.5f;
anim.repeatCount =1;
anim.removedOnCompletion = NO;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
anim.fillMode=kCAFillModeForwards;
[imView.layer addAnimation:anim forKey:@"position.x"];
[sender.layer addAnimation:anim forKey:@"position.x"];
sender.layer.position=CGPointMake(point.x+50.0,sender.layer.position.y);
即使将 removedOnCompletion 设置为 no,它也会跳回这一事实令人头疼。还在玩。
【讨论】:
将removeOnCompletion
设置为NO
几乎从来都不是正确的答案。如果您认为这是答案,您应该观看来自 WWDC 2011 的 Core Animation Essentials video。
是的。这完全没有改变。
最后缺少的是 anim.fillMode=kCAFillModeForwards;
说真的,看视频。您建议的解决方案不会更新模型层。如果 Tanner 想要为按钮设置动画,按钮将停止工作,因为命中测试是在模型层而不是表示层上执行的。以上是关于使用核心动画在屏幕上移动 UIImage的主要内容,如果未能解决你的问题,请参考以下文章