UIViewPropertyAnimator 不考虑持续时间和延迟参数

UIViewPropertyAnimator not respecting duration and delay parameters

我的应用程序中有一个非常奇怪的问题。我正在使用 UIViewPropertyAnimatorUIImageView 中不断变化的图像制作动画。

听起来像是微不足道的任务,但出于某些原因,我的视图最终会立即更改图像,所以我最终得到的图像以光速闪烁,而不是给定持续时间和延迟参数。

代码如下:

private lazy var images: [UIImage?] = [
    UIImage(named: "widgethint"),
    UIImage(named: "shortcuthint"),
    UIImage(named: "spotlighthint")
]
private var imageIndex = 0
private var animator: UIViewPropertyAnimator?

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    animator = repeatingAnimator()
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    animator?.stopAnimation(true)
}

private func repeatingAnimator() -> UIViewPropertyAnimator {
    return .runningPropertyAnimator(withDuration: 2, delay: 6, options: [], animations: {
        self.imageView.image = self.images[self.imageIndex]
    }, completion: { pos in
        if self.imageIndex >= self.images.count - 1 {
            self.imageIndex = 0
        } else {
            self.imageIndex += 1
        }
        self.animator = self.repeatingAnimator()
    })
}

因此,根据代码动画应该需要 2 秒才能完成并在延迟 6 秒后开始,但它会立即开始并需要几毫秒才能完成,所以我最终得到了可怕的幻灯片。为什么会发生?

我也试过使用 UIViewPropertyAnimator(duration: 2, curve: .linear) 并调用 repeatingAnimator().startAnimation(afterDelay: 6) 但结果是一样的。

好吧,我已经弄明白了,但是使用"Modern"动画API无法完成这么简单的任务还是有点烦人。

因此,UIViewPropertyAnimator 显然不支持 UIImageView 中的动画图像,在调试过程中,我尝试对视图的背景颜色进行动画处理,它按预期工作。所以我不得不使用 Timer 而不是旧的 UIView.transition(with:) 方法

这是工作代码:

private let animationDelay: TimeInterval = 2.4

private var animationTimer: Timer!

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    setAnimation(true)
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    setAnimation(false)
}

private func setAnimation(_ enabled: Bool) {
    guard enabled else {
        animationTimer?.invalidate()
        animationTimer = nil
        return
    }
    animationTimer = Timer.scheduledTimer(withTimeInterval: animationDelay, repeats: true) { _ in
        UIView.transition(with: self.imageView, duration: 0.5, options: [.curveLinear, .transitionCrossDissolve], animations: {
            self.imageView.image = self.images[self.imageIndex]
        }, completion: { succ in
            guard succ else {
                return
            }
            if self.imageIndex >= self.images.count - 1 {
                self.imageIndex = 0
            } else {
                self.imageIndex += 1
            }
        })
    }
}

希望它能在将来为某些人省去一些麻烦