1

我试图让属性动画师在呈现视图控制器时启动动画。现在动画正在播放,但是UIViewPropertyAnimator不响应添加到它的完成处理程序。

  • UIVisualEffectView子类。
import UIKit

final class BlurEffectView: UIVisualEffectView {
    
    deinit {
    animator?.stopAnimation(true)
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        effect = nil
        animator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [unowned self] in
          self.effect = theEffect
        }
        animator?.pausesOnCompletion = true
   }

    private let theEffect: UIVisualEffect = UIBlurEffect(style: .regular)
    var animator: UIViewPropertyAnimator?

}

  • 第一个视图控制器
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func doSomething(_ sender: UIButton) {
        let vc = storyboard?.instantiateViewController(identifier: "second") as! SecondVC
        vc.modalPresentationStyle = .overFullScreen

        present(vc, animated: false) { //vc presentation completion handler
            
            //adding a completion handler to the UIViewPropertyAnimator
            vc.blurView.animator?.addCompletion({ (pos) in
                print("animation complete") //the problem is that this line isn't executed 
            })
            vc.blurView.animator?.startAnimation()
        }
    }
    
}
  • 第二个视图控制器
import UIKit

class SecondVC: UIViewController {

    @IBOutlet weak var blurView: BlurEffectView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

这里UIViewPropertyAnimator完成处理程序是在第二个视图控制器(具有视觉效果视图的控制器)出现之后添加的。我曾尝试将完成处理程序移动到不同的地方viewDidLoadviewDidAppear但似乎没有任何效果。

4

2 回答 2

3

整个事情似乎设计不正确。

draw(_ rect:)不是初始化您的动画师*的地方,我对正在发生的事情的最佳猜测vc.blurView.animator?nil当您尝试启动它时(您是否验证它不是?)。

相反,您的视图类可能如下所示**:

final class BlurEffectView: UIVisualEffectView {
    func fadeInEffect(_ completion: @escaping () -> Void) {
        UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.5, delay: 0, options: []) {
            self.effect = UIBlurEffect(style: .regular)
        } completion: { _ in
            completion()
        }
    }
}

你会像这样执行你的动画:

present(vc, animated: false) { //vc presentation completion handler
    vc.blurView.fadeInEffect {
        // Completion here
    }
}

*draw(_ rect:)每次你让系统知道你需要重绘你的视图时都会被调用,并且你应该在里面使用 CoreGraphics 来绘制你的视图的内容,这不是你在这里做的事情。

**由于您没有使用属性动画师的任何更高级功能,因此似乎没有必要将其存储在 ivar 中。

于 2021-05-31T11:20:21.130 回答
1

问题是您设置pausesOnCompletion为true。这会导致不调用完成处理程序。

如果您确实需要将其设置为 true,则需要使用 KVO 来观察该isRunning属性:

// property of your VC
var ob: NSKeyValueObservation?

...

self.ob?.invalidate()
self.ob = vc.blurView.animator?.observe(\.isRunning, options: [.new], changeHandler: { (animator, change) in
    if !(change.newValue!) {
        print("completed")
    }
})
vc.blurView.animator?.startAnimation()

正如 EmilioPelaez 所说,你不应该初始化你的animatorin draw。同样,如果您确实有使用 的理由pausesOnCompletion = true,请将它们设置在惰性属性中:

lazy var animator: UIViewPropertyAnimator? = {
    let anim = UIViewPropertyAnimator(duration: 1, curve: .linear) { [unowned self] in
        self.effect = self.theEffect
    }
    anim.pausesOnCompletion = true
    return anim
}()

self.effect = nil可以在初始化程序中设置。

于 2021-05-31T11:39:49.293 回答