如何为 UIView 关键帧动画设置动画曲线(`func UIView.animateKeyframes()`)

Posted

技术标签:

【中文标题】如何为 UIView 关键帧动画设置动画曲线(`func UIView.animateKeyframes()`)【英文标题】:How do I set animation curves for UIView keyframe animations (`func UIView.animateKeyframes()`) 【发布时间】:2021-06-20 13:52:26 【问题描述】:

UIView 关键帧动画让您可以创建通过一系列步骤进行的视图动画。函数animateKeyframes(withDuration:delay:options:animations:completion:) 有一个UIView.KeyframeAnimationOptions 类型的选项参数。我希望这能让我选择一个整体时序曲线以应用于组合的动画集。它似乎应用了缓入缓出的默认动画曲线,并且似乎不允许您像UIView.animate() 系列方法那样指定时序曲线。如果我想要线性时序,只是缓入或缓出怎么办?

【问题讨论】:

【参考方案1】:

有趣的是,UIView.animate() 方法(UIView.AnimationOptions 类型)的动画选项如果你能弄清楚如何将它们传递给 animateKeyframes(withDuration:delay:options:animations:completion:) 就可以工作。不幸的是,没有现有的时间曲线常数,如线性、缓入或缓出。 This SO answer 展示了如何将值从 UIView.AnimationOptions 常量“强制”到 UIView.KeyframeAnimationOptions OptionSet:

extension UIViewKeyframeAnimationOptions 

    init(animationOptions: UIViewAnimationOptions) 
        rawValue = animationOptions.rawValue
    


我更进一步,为不同的计时函数定义了常数。 (我不知道为什么苹果没有定义这些。这看起来很荒谬,但你就是这样。)

我对@9​​87654331@ 的扩展如下所示:

extension UIView.KeyframeAnimationOptions 
    static var curveLinear: UIView.KeyframeAnimationOptions =
        UIView.KeyframeAnimationOptions(rawValue:UIView.AnimationOptions.curveLinear.rawValue)

    static var curveEaseInOut: UIView.KeyframeAnimationOptions =
        UIView.KeyframeAnimationOptions(rawValue:UIView.AnimationOptions.curveEaseInOut.rawValue)

    static var curveEaseIn: UIView.KeyframeAnimationOptions =
        UIView.KeyframeAnimationOptions(rawValue:UIView.AnimationOptions.curveEaseIn.rawValue)

    static var curveEaseOut: UIView.KeyframeAnimationOptions =
        UIView.KeyframeAnimationOptions(rawValue:UIView.AnimationOptions.curveEaseOut.rawValue)

    init(animationOptions: UIView.AnimationOptions) 
        self.init(rawValue: animationOptions.rawValue)
    

使用该扩展,您可以像调用 UIView.animate() 方法一样使用时序曲线值:

UIView.animateKeyframes(withDuration: 2.0, delay: 0, options: [.curveLinear]) 
    // Your animation keyframe steps here

在 UIView.AnimationOptions 中定义的其他一些标志也可能对UIView.KeyframeAnimationOptions 有效。您可以使用将UIView.AnimationOptions 映射到UIView.KeyframeAnimationOptions 的方法,或者像我添加时序曲线标志一样向UIView.KeyframeAnimationOptions 添加额外的标志。


编辑:

我很好奇 UIView.animate()animateKeyframes() 选项中的标志是否匹配。我编写了一些代码来记录两个选项集的所有值,这就是我得到的:

KeyframeAnimationOptions:
option value 0x00000001 = layoutSubviews
option value 0x00000002 = allowUserInteraction
option value 0x00000004 = beginFromCurrentState
option value 0x00000008 = repeat
option value 0x00000010 = autoreverse
option value 0x00000020 = overrideInheritedDuration
option value 0x00000200 = overrideInheritedOptions

option value 0x00000000 = calculationModeLinear
option value 0x00000400 = calculationModeDiscrete
option value 0x00000800 = calculationModePaced
option value 0x00000C00 = calculationModeCubic
option value 0x00001000 = calculationModeCubicPaced

UIView.AnimationOptions:
option value 0x00000001 = layoutSubviews
option value 0x00000002 = allowUserInteraction
option value 0x00000004 = beginFromCurrentState
option value 0x00000008 = repeat
option value 0x00000010 = autoreverse
option value 0x00000020 = overrideInheritedDuration
option value 0x00000200 = overrideInheritedOptions

option value 0x00000040 = overrideInheritedCurve
option value 0x00000080 = allowAnimatedContent
option value 0x00000100 = showHideTransitionViews
option value 0x00000000 = curveEaseInOut
option value 0x00010000 = curveEaseIn
option value 0x00020000 = curveEaseOut
option value 0x00030000 = curveLinear
option value 0x00100000 = transitionFlipFromLeft
option value 0x00200000 = transitionFlipFromRight
option value 0x00300000 = transitionCurlUp
option value 0x00400000 = transitionCurlDown
option value 0x00500000 = transitionCrossDissolve
option value 0x00600000 = transitionFlipFromTop
option value 0x00700000 = transitionFlipFromBottom
option value 0x03000000 = preferredFramesPerSecond60
option value 0x07000000 = preferredFramesPerSecond30

两组中的前 7 个标志具有相同的名称和相同的值。 KeyframeAnimationOptions 的 0 值为 calculationModeLinear,而 UIView.AnimationOptions 的值为 curveEaseInOut。它会导致关键帧和“常规”UIView 动画的缓入/缓出计时。

所有其他常量的值在两个选项集中都是唯一的,这表明其他一些 UIView.AnimationOptions 可能适用于关键帧动画。不过,我只测试了时序曲线值,它们都按预期工作。

编辑#2:

关键帧动画标志(如calculationModeLinear、calculationModeCubic和calculationModeCubicPaced)和视图动画标志(如curveLinear、curveEaseInOut等)如何交互并不是很明显,因为关键帧动画标志也与动画时间有关.我写了一个测试应用程序来看看他们是怎么做的。事实证明,UIView.AnimationOptions 时序曲线标志会影响整个关键帧动画的整体时序。 (整个关键帧动画开始和停止的方式。)

您可以从 githubhere 下载示例项目。

很难看到缓入/缓出 UIView 动画时间与立方关键帧动画选项之一相结合。使用关键帧计算模式线性模式更容易看到缓入/缓出。

以下是该组合的视频:

(请注意青色正方形在返回到起点之前如何在动画矩形的右下角停止。)

【讨论】:

以上是关于如何为 UIView 关键帧动画设置动画曲线(`func UIView.animateKeyframes()`)的主要内容,如果未能解决你的问题,请参考以下文章

如何为 UIView 动画设置相同的速度

如何为每个属性定义具有不同计时功能的 CSS 动画?

如何为嵌入在 UITableViewCell 中的 UIView 设置动画

如何为 UICollectionViewCell 的帧更改设置动画

当UIVIew隐藏在sameView中时,如何为UIview设置动画

如何为手动“动画”重新排队对 UIView drawRect 的请求