UIViewPropertyAnimator 停止重复

UIViewPropertyAnimator stop repeating

我在工厂中有这段代码 class 到 return UIViewPropertyAnimators 何时何地使用:

class AnimatorFactory {

    @discardableResult
    static func spinSpindle(spindle: UIView) -> UIViewPropertyAnimator {
        let spinSpindleAnimator = UIViewPropertyAnimator(duration: 1.0, curve: .linear)

        spinSpindleAnimator.addAnimations {
            spindle.transform = CGAffineTransform(rotationAngle: .pi)
        }
        spinSpindleAnimator.addCompletion{ position in
            print("spinSpindle.complete: \(position.rawValue)")
            spindle.transform = .identity
            self.spinSpindle(spindle: spindle)
        }
        spinSpindleAnimator.startAnimation()

        return spinSpindleAnimator
    }
...

代码创建了一个 UIViewPropertyAnimator 允许永久动画视图(一个不断旋转和旋转的视图)。它通过在完成块中再次调用自己来做到这一点。我现在遇到的问题是我无法使用 UIViewPropertyAnimator.stopAnimation(true) 停止动画。

stopAnimation(_ withoutFinishing:) 值中的 true 旨在确保动画 return 进入 UIViewAnimatingState.inactive 状态,而无需使用 [=20 执行任何清理=].

当我调用 stopAnimation(true) 时,动画不会停止。它是这样称呼的:

    print("\(spindleAnimator.description)")
    spindleAnimator.stopAnimation(true)
    print("\(spindleAnimator.description)")

以上代码由用户点击动画视图触发并输出:

<UIViewPropertyAnimator(0x600001c1c100) [inactive] interruptible>
<UIViewPropertyAnimator(0x600001c1c900) [inactive] interruptible>

对我来说,这表明 spindleAnimator 指的是不同的 UIViewPropertyAnimator,因为 AnimatorFactory.spinSpindle(spindle:) 静态方法中的 "recursive" 调用。我可能弄错了。

本质上,我正在寻求帮助以创建一个真正交互式和重复的动画。到目前为止,我一直遇到难以置信的麻烦,但我不会抱怨,因为我学到了很多东西。但是,我需要一些帮助,通过找到一个有效的 stopAnimation(withoutFinishing:) 调用来将它们联系在一起。

谢谢!

编辑:

另一个有趣的事实是,如果我在它完成第一次旋转之前(换句话说,在执行完成块之前)单击主轴,我可以停止动画。这让我相信 "recursive" 对 spinSpindle(spindle:) 的调用会创建另一个 UIViewPropertyAnimator,我无法为其调用 stopAnimation(withoutFinishing:)。虽然,我不认为我明白这是怎么回事...

我通过每次调用 spinSpindle(spindle:) 时打印 spinSpindleAnimator.description 来测试这个理论:

class AnimatorFactory {

    @discardableResult
    static func spinSpindle(spindle: UIView) -> UIViewPropertyAnimator {
        let spinSpindleAnimator = UIViewPropertyAnimator(duration: 1.0, curve: .linear)

        spinSpindleAnimator.addAnimations {
            spindle.transform = CGAffineTransform(rotationAngle: .pi)
        }
        spinSpindleAnimator.addCompletion{ position in
            print("(\(spinSpindleAnimator.description)) spinSpindle.complete: \(position.rawValue)")
            spindle.transform = .identity
            self.spinSpindle(spindle: spindle)
        }
        spinSpindleAnimator.startAnimation()

        return spinSpindleAnimator
    }

它给出

(<UIViewPropertyAnimator(0x600001b20300) [unknown] running interruptible>) spinSpindle.complete: 0
(<UIViewPropertyAnimator(0x600001b28b00) [unknown] running interruptible>) spinSpindle.complete: 0
(<UIViewPropertyAnimator(0x600001b38600) [unknown] running interruptible>) spinSpindle.complete: 0
(<UIViewPropertyAnimator(0x600001b31000) [unknown] running interruptible>) spinSpindle.complete: 0
(<UIViewPropertyAnimator(0x600001b38300) [unknown] running interruptible>) spinSpindle.complete: 0
(<UIViewPropertyAnimator(0x600001b38600) [unknown] running interruptible>) spinSpindle.complete: 0
(<UIViewPropertyAnimator(0x600001b38700) [unknown] running interruptible>) spinSpindle.complete: 0
(<UIViewPropertyAnimator(0x600001b20600) [unknown] running interruptible>) spinSpindle.complete: 0
...

证实了我的怀疑。

您无法停止动画,因为您持有由您的函数创建和返回的 UIViewPropertyAnimator 的第一个对象,但是您的函数的这一行每次都会创建 UIViewPropertyAnimator 的新对象

self.spinSpindle(spindle: spindle)

而且你不holding/returning这个对象到任何地方。 您总是对从函数返回的第一个对象调用 stopAnimation 函数。这就是为什么您可以在主轴完成第一次旋转之前点击主轴之前停止动画,而不是在调用完成块之后。