Ios Swift 在非线性路径中动画视图

Posted

技术标签:

【中文标题】Ios Swift 在非线性路径中动画视图【英文标题】:Ios Swift Animate a view in non linear path 【发布时间】:2015-12-02 13:55:45 【问题描述】:

我正在尝试通过非线性路径为 UIView 设置动画(我不是在尝试绘制路径本身),如下所示:

视图的初始位置是使用尾随和底部约束确定的(viewBottomConstraint.constant == 100 & viewTrailingConstraint.constant == 300) 我正在像这样使用UIView.animatedWithDuration

viewTrailingConstraint.constant = 20
viewBottomConstraint.constant = 450
UIView.animateWithDuration(1.5,animation:
    self.view.layoutIfNeeded()
,completition:nil)

但它以线性路径为视图设置动画。

【问题讨论】:

你不使用核心动画吗? 要沿路径移动对象,您应该使用 CAKeyFrame 动画。可能您需要在开始之前删除约束并在最后再次添加它们。 objc.io/issues/12-animations/animations-explained 不错的选择,但是当我只知道对象的开始和最终位置时如何创建路径? 【参考方案1】:

你可以使用带路径的关键帧动画

    let keyFrameAnimation = CAKeyframeAnimation(keyPath:"position")
    let mutablePath = CGPathCreateMutable()
    CGPathMoveToPoint(mutablePath, nil,50,200)
    CGPathAddQuadCurveToPoint(mutablePath, nil,150,100, 250, 200)
    keyFrameAnimation.path = mutablePath
    keyFrameAnimation.duration = 2.0
    keyFrameAnimation.fillMode = kCAFillModeForwards
    keyFrameAnimation.removedOnCompletion = false
    self.label.layer.addAnimation(keyFrameAnimation, forKey: "animation")

动图

关于这个功能

void CGContextAddQuadCurveToPoint (
   CGContextRef _Nullable c,
   CGFloat cpx,
   CGFloat cpy,
   CGFloat x,
   CGFloat y
);

(cpx,cpy)是控制点,(x,y)是终点

【讨论】:

【参考方案2】:

Leo 使用 Core Animation 和CAKeyframeAnimation 的回答很好,但它在视图的“表示层”上操作,只会创建将视图移动到新位置的外观。您需要添加额外的代码才能在动画完成后将视图实际移动到其最终位置。此外,Core Animation 复杂且令人困惑。

我建议使用 UIView 方法 animateKeyframesWithDuration:delay:options:animations:completion:。您可能希望使用选项值 UIViewKeyframeAnimationOptionCalculationModeCubic,它会导致对象沿着通过所有点的弯曲路径移动。

您在视图上调用它,然后在动画块中,多次调用addKeyframeWithRelativeStartTime:relativeDuration:animations:,将视图移动到曲线上的点。

我在 github 上有一个示例项目,展示了这种技术和其他技术。它叫KeyframeViewAnimations(链接)

编辑:

(请注意,像animateKeyframes(withDuration:delay:options:animations:completion:) 这样的 UIView 动画实际上并没有沿您指定的路径为您的视图设置动画。它们使用表示层,就像 CALayer 动画一样,而表示层使视图看起来像是沿着指定路径,它实际上在动画开始时从开始位置捕捉到结束位置。UIView 动画确实将视图移动到其目标位置,其中 CALayer 动画移动表示层,而根本不移动层/视图。)

Leo 的基于路径的 UIView 动画与我使用 UIView animateKeyframes(withDuration:delay:options:animations:completion:) 的答案之间的另一个细微差别是 CGPath 曲线是三次或二次贝塞尔曲线,而我的答案使用另一种称为 Katmull-Rom 样条曲线的曲线进行动画处理。贝塞尔路径在它们的起点和终点开始和结束,并被吸引到但不通过它们的中间控制点。 Catmull-Rom 样条生成一条通过其每个控制点的曲线。

【讨论】:

在 Swift 3 中添加 UIView.animateKeyframes 使这个答案成为更合适的解决方案。 Core Animation 为寻找 UIView 基本动画的原始海报增加了不必要的复杂性。 @ZacSketches,同意,UIView.animateKeyframes 是一种更简单、更高级的视图动画方法,而且计算起来也不那么复杂。不过,有一点需要注意:animateKeyFrames 是一项操作系统功能,并非特定于 Swift 3。如果我没记错的话,它是在 ios 7 中添加的。我认为那是在 Swift 出现之前。所以每个版本的 Swift 都允许你调用animateKeyFrames

以上是关于Ios Swift 在非线性路径中动画视图的主要内容,如果未能解决你的问题,请参考以下文章

沿着图层的特定路径快速制作动画

列表视图滚动时在屏幕底部隐藏线性布局

几种常用的Interpolator(插值器)的动画效果

iOS Core Animation Advanced Techniques-显式动画

iOS Swift UIView 动画跳回到开头

iOS Swift:在同一个View Controller上进行过渡动画