UIView 关键帧动画时间不符合预期

UIView keyframe animation timing not as expected

我有一些动画(可在操场上测试):

import UIKit
import XCPlayground
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution


let view = UIView()
view.frame = .init(x: 0, y: 0, width: 150, height: 150)
view.backgroundColor = .orange
let hand = UIView()
view.addSubview(hand)
hand.frame = .init(x: 0, y: 0, width: 10, height: 10)
hand.center = view.center
hand.backgroundColor = .green
PlaygroundPage.current.liveView = view

let fadeDuration: TimeInterval = 0.4
let translationDuration: TimeInterval = 1
let resetDuration: TimeInterval = 0.25
let duration: TimeInterval =
    7 * fadeDuration +
    4 * translationDuration +
    3 * resetDuration
var currentTime: TimeInterval  = 0.0

func addKey(_ animations: @escaping () -> Void, animationTime: TimeInterval) {
    UIView.addKeyframe(withRelativeStartTime: currentTime / duration, relativeDuration: animationTime / duration, animations: animations)
    currentTime += animationTime
}

func fadeIn() {
    addKey({
        hand.alpha = 1
    }, animationTime: fadeDuration)
}

func fadeOut() {
    addKey({
        hand.alpha = 0
    }, animationTime: fadeDuration)
}

func translate(_ direction: (CGFloat) -> CGFloat) {
    let x = direction(50)
    addKey({
        hand.transform = .init(translationX: x, y: 0)
    }, animationTime: translationDuration)
}

func reset() {
    addKey({
        hand.transform = .identity
    }, animationTime: 0)
    currentTime += resetDuration
}

UIView.animateKeyframes(withDuration: duration, delay: 0, options:  .calculationModeLinear) {
    translate(-)
    fadeOut()
    reset()
    fadeIn()
    translate(-)
    fadeOut()
    reset()
    fadeIn()
    translate(+)
    fadeOut()
    reset()
    fadeIn()
    translate(+)
    fadeOut()
} completion: { _ in
    PlaygroundPage.current.finishExecution()
}

我希望每一个 translate() 动画都以相同的速度 运行,但由于某些原因第一个和最后一个特别慢,尽管使用 .calculationModeLinear

如何使 translationDuration / duration 为常数时间?

calculationModeLinear 不同于 curveLinear。听起来你想要后者。默认情况下,您使用的是 curveEaseInOut,因此在接近整体开始和结束时,运动当然会变慢。

需要一些 hanky panky 来克服 Swift 的严格输入。示例代码:

let animationOptions: UIView.AnimationOptions = .curveLinear
let keyframeAnimationOptions = UIView.KeyframeAnimationOptions(rawValue: animationOptions.rawValue)
UIView.animateKeyframes(withDuration: duration, delay: 0.1, options:  keyframeAnimationOptions) {