Tigran Iskandaryan
Tigran Iskandaryan

Reputation: 1451

The completion block of UIView animation gets called before the animation is finished

I have a custom animator for view controller interactive transition. There is also a blur effect that is set to nil depending on the transition progress. The effect's animation code is the following:

@objc func blurEffectDissmisal() {

    UIView.animate(withDuration: dismissAnimator.durationOfAnimation + 1, animations: {
        self.blurEffectView?.effect = nil
    }) { (done) in
        if (done) {
       self.blurEffectView?.removeFromSuperview()
        }
    }
}

I call it by a notification, which is called on the second view controller when the transition from it to the first one starts.

However, I have a problem here. The completion block is called before the animation ends. When I run the transition for the first time (without canceling it) it works fine, but during the subsequents runs it doesn't.

I had also tried to add the animation to my animator but it didn't work out, either.

Moreover, the completion block gets called before the actual animation ends when I cancel the transition (in this case, I understand why but can't figure out how to make it move backwards. Maybe I should create a reverse animation in a completion block?)

I have tried the suggestion from this answer as you can see, but doesn't help.

If you know how this problem could be solved, I would really appreciate your help.

Upvotes: 3

Views: 2384

Answers (3)

Sateesh Pasala
Sateesh Pasala

Reputation: 998

Use a delay before calling animate function .

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        UIView.animate(withDuration: 2.0,delay: 0, animations: {
            self.frame.origin.x = -2000
        }) { (done) in
            if(done){
                self.removeFromSuperview()
            }
            
        }
    }

Upvotes: 2

Nitish
Nitish

Reputation: 14123

  UIView.animate(withDuration: 1, animations: {
                self.blurEffectView?.frame = CGRect(x: self.blurEffectView?.frame.origin.x, y: self.view.frame.size.height, width: self.blurEffectView?.frame.size.width, height: self.blurEffectView?.frame.size.height)
            }, completion: {
                (value: Bool) in
                self.blurEffectView?.removeFromSuperview()
            })  

Using the same animation (on UIView) I am able to achieve this :

enter image description here

Upvotes: 0

Dominik Bucher
Dominik Bucher

Reputation: 2167

I've created a playground where you can take a look at this change, just create new playground, click on the assistant editor (top left corner, two joined circles) and take a look at the animation. This should do.

import PlaygroundSupport
import UIKit


let rect = CGRect(x: 0, y: 0, width: 40, height: 40)
let view = UIView(frame: rect )
view.backgroundColor = UIColor.yellow
let label = UILabel(frame: rect)
label.text = "A"
label.textAlignment = .center
view.addSubview(label)

let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurEffectView)

PlaygroundPage.current.liveView = view

UIView.animate(withDuration: 4, animations: {
    blurEffectView.alpha = 0
}) { (done) in
    if (done) {
        blurEffectView.removeFromSuperview()
    }
}

The problem you are facing is not that the UIView.animate doesn't do it's job, it's just because you are setting the view to nil is not animable. Like imagine deleting someething could be animated...

Upvotes: 0

Related Questions