1

我编写了以下小演示,它通过一次旋转 90° 来旋转 UIView 360°。这意味着动画有 4 个步骤

我希望它在第一个动画步骤中缓入,在中间 2 个步骤中以稳定的速度前进,然后在最后一步使用缓出时间,使其滑行停止。代码如下。这是它使用的动画时间:

Animating to  90°, options = curveEaseIn
Animating to 180°, options = curveLinear
Animating to 270°, options = curveLinear
Animating to   0°, options = curveEaseOut

每个步骤需要 1/2 秒,总持续时间为 2 秒。但是,由于第一步和最后一步需要 1/2 秒,但以较慢的速度开始/结束,这些动画步骤的“全速”部分明显快于使用线性时序的中间 2 个动画步骤。结果动画不流畅。

是否有一种简单的方法来调整步骤时间,使动画中的每个步骤都以与开始/结束步骤相同的速度运行,从而缓入/缓出时间?

我想我可以改为创建一个关键帧动画,其中整个动画使用缓入/缓出时间,而动画中的中间步骤使用线性时间。然而,似乎应该有一种简单的方法可以将其从逐步动画中解脱出来。

class ViewController: UIViewController {
    
    var rotation: CGFloat = 0
    @IBOutlet weak var rotateableView: RotatableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func handleRotateButton(_ sender: UIButton? = nil) {
        let duration = 0.5
        var optionsValue: (options: UIView.AnimationOptions, optionsName: String) = (.curveLinear, "curveLinear")
        self.rotation = fmod(self.rotation + 90, 360)
        sender?.isEnabled = false
        if self.rotation == 0 {
            optionsValue = (.curveEaseOut, "curveEaseOut") // Ending the animatino, so ease out.
        } else if self.rotation == 90 {
            optionsValue = (.curveEaseIn, "curveEaseIn") // Beginning the animation, so ease in
        }
        let rotation = String(format:"%3.0f", self.rotation)
        print("Animating to \(rotation)°, options = \(optionsValue.optionsName)")
        UIView.animate(withDuration: duration, delay: 0, options: optionsValue.options) {
            let angle = self.rotation / 180.0 * CGFloat.pi
            self.rotateableView.transform = CGAffineTransform.init(rotationAngle: angle)
        } completion: { finished in
            if self.rotation != 0 {
                self.handleRotateButton(sender)
            } else {
                self.rotation = 0
                sender?.isEnabled = true
            }
        }
    }
}
4

1 回答 1

0

好吧,我不知道如何调整一系列逐步动画的时间,以使它们缓和到第一步,对中间步骤使用线性时间,并在最后一步使用缓出。

但是,关键帧动画显然默认为整个动画的缓入缓出时间。这使得为​​整个步骤序列创建缓入缓出时间非常容易。它看起来像这样:

@IBAction func handleRotateButton(_ sender: UIButton? = nil) {

    UIView.animateKeyframes(withDuration: 1.5, delay: 0, options: []) {
        for index in 1...4 {
            let startTime = Double(index-1) / 4
            UIView.addKeyframe(withRelativeStartTime: startTime,
                               relativeDuration: 0.25,
                               animations: {
                                let angle: CGFloat = CGFloat(index) / 2 * CGFloat.pi
                                self.rotateableView.transform = CGAffineTransform.init(rotationAngle: angle)
                               }
            )
        }
    } completion: { completed in
        self.rotation = 0
        sender?.isEnabled = true
    }
}

此外,如果UIView.animateKeyframes()animate(withDuration:delay:options:animations:completion:)只是UIView.KeyframeAnimationOptions使用原始值从UIView.AnimationOptions. 你可以用这样的扩展来做到这一点:

extension UIView.KeyframeAnimationOptions {
    init(animationOptions: UIView.AnimationOptions) {
        self.init(rawValue: animationOptions.rawValue)
    }
}

然后你可以使用这样的代码来创建KeyframeAnimationOptionsAnimationOptions

let keyframeOptions = UIView.KeyframeAnimationOptions(animationOptions: .curveLinear)
于 2021-06-19T22:11:29.043 回答