I'm trying to get a property animator to start animation when a View Controller is presented.
Right now the animation is playing however the UIViewPropertyAnimator
doesn't respond to the completion handler added to it.
UIVisualEffectView
sub-class.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()
}
}
Here the UIViewPropertyAnimator
completion handler is added after the Second View Controller(controller with visual effect view) is presented. I have tried moving the completion handler to different places like viewDidLoad
and viewDidAppear
but nothing seems to work.
This whole thing seems incorrectly designed.
draw(_ rect:)
is not the place to initialize your animator*, my best guess at what's happening is that vc.blurView.animator?
is nil
when you try to start it (have you verified that it isn't?).
Instead, your view class could look like this**:
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()
}
}
}
And you would execute your animation like this:
present(vc, animated: false) { //vc presentation completion handler
vc.blurView.fadeInEffect {
// Completion here
}
}
*draw(_ rect:)
gets called every time you let the system know that you need to redraw your view, and inside you're supposed to use CoreGraphics to draw the content of your view, which is not something you're doing here.
**Since you're not using any of the more advanced features of the property animator, it doesn't seem necessary to store it in an ivar.