Skip to content

Toggling UIView visibility using UIViewPropertyAnimator

We all know the UIView’s animateWithDuration:animations:completion: type method. It is very easy to use and its support dates back to iOS 4. However adopting this method has one major drawback: the impossibility to modify the animation without having to incur in some… headaches.

Luckily starting from iOS 10, Apple introduced UIViewPropertyAnimator, which allows you to easily create animations that can be dynamically modified.

Let’s see with an example how we can use this class to create a mechanism to toggle a bottom bar’s visibility when the user taps the screen. For starters we are going to need to declare some vars in our ViewController.

class ViewController {
    ... 
    let kBottomBarHeight : CGFloat = 100
    var bottomBarAnimator: UIViewPropertyAnimator!
    var bottomBar: UIView!
    var bottomBarIsHidden: Bool = false
    ...
}

The bottomBarAnimator var is the object responsible for starting and controlling the animation.

Then we assume that bottomBar is a simple plain UIView with some black semi-transparent background whose visibility is determined by the boolean var bottomBarIsHidden.

To toggle the visibility of the bottom bar we need to add a tap gesture recognizer to the main view, so that when the user taps the screen, the toggleBottomBar method is called.

Let’s make this real by writing some code.

class ViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        //place the bottom bar at the bottom
        bottomBar = UIView(frame: CGRect(x: 0.0, y: view.bounds.height-kBottomBarHeight, width: view.bounds.size.width, height: kBottomBarHeight))
        //give the bar a black semi-transparent background so that we can see it
        bottomBar.backgroundColor = .black.withAlphaComponent(0.35)
        view.addSubview(bottomBar)

        //add a tap gesture recognizer that triggers the toggling of the bottom bar
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(userDidTap))
        tapGestureRecognizer.numberOfTapsRequired = 1
        tapGestureRecognizer.numberOfTouchesRequired = 1
        view.addGestureRecognizer(tapGestureRecognizer)
    }
    //the action method triggered by the tap gesture recognizer
    @objc func userDidTap(_ gesture: UITapGestureRecognizer) {
        if gesture.state == .recognized {
            toggleBottomBar()
        }
    }
}

Now that we initialized the basic components of our class we just need to implement the toggleBottomBar() method, which is triggered when he user taps the screen.

class ViewController {
    ...   
    func toggleBottomBar() {
        // stop the animation by using the animator if initialized
        bottomBarAnimator?.stopAnimation(true)
        // toggle the var that determines if our bottom bar will be hidden or not
        bottomBarIsHidden.toggle()
        bottomBarAnimator = 
            UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.5, 
                                                                  delay: 0.0, 
                                                                options: .curveEaseIn,
                                                             animations: { [weak self] in
            guard let self = self else { return }
            self.bottomBar.alpha = self.bottomBarIsHidden ? 0.0 : 1.0
        })
    }
}

The algorithm cancels the toggling animation using the bottomBarAnimator?.stopAnimation(true), right before starting a new animation. Then bottomBarIsHidden var is toggled and based on its value the target alpha value for the animation is determined.