SwiftER
SwiftER

Reputation: 1255

Swift UITabBarController hide with animation

I'm trying to add animation to my tabBarController when hidden. Im able to accomplish this effect with the navigationBarController by using self.navigationController?.isNavigationBarHidden = true. I'm able to hide the tabBar by using self.tabBarController?.tabBar.isHidden = true but i do not get the animation how can I do this thank you in advance.

Upvotes: 8

Views: 15016

Answers (9)

Luis Ascorbe
Luis Ascorbe

Reputation: 2099

Here's a quick animation to show/hide from the bottom of the screen (tweak to your taste):

public extension UITabBar {
    func hideWithAnimation() {
        DispatchQueue.main.async {
            guard !self.isHidden else { return }
            UIView.transition(with: self, duration: 0.2, options: .curveEaseIn,
                              animations: { () -> Void in
                self.frame.origin.y += self.frame.size.height
            }, completion: { _ in
                self.isHidden = true
            })
        }
    }

    func showWithAnimation() {
        DispatchQueue.main.async {
            guard self.isHidden else { return }
            UIView.transition(with: self, duration: 0.15, options: .curveEaseOut,
                              animations: { () -> Void in
                self.isHidden = false
                self.frame.origin.y -= self.frame.size.height
            }, completion: nil)
        }
    }
}

If you want to use this from SwiftUI, you will have to use something like SwiftUI-Introspect to get the UITabBarController.

Note: I added DispatchQueue.main.async because it can be called from another thread in my case, you should check if you need it and remove it if not.

Upvotes: 0

Rasheed
Rasheed

Reputation: 181

Here is a simple extension :

func setTabBar(hidden:Bool) {
    guard let frame = self.tabBarController?.tabBar.frame else {return }
    if hidden {
        UIView.animate(withDuration: 0.3, animations: {
            self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: frame.origin.y + frame.height, width: frame.width, height: frame.height)
        })
    }else {

        UIView.animate(withDuration: 0.3, animations: {
            self.tabBarController?.tabBar.frame = UITabBarController().tabBar.frame

        })
    }
}

Upvotes: 1

Federico Malagoni
Federico Malagoni

Reputation: 792

You have to add UIView transitionWithView class func

Swift 2

func hideTabBarWithAnimation() -> () {
    UIView.transitionWithView(tableView, duration: 1.0, options: .TransitionCrossDissolve, animations: { () -> Void in
        self.tabBarController?.tabBar.hidden = true
    }, completion: nil)
}

Swift 3, 4, 5

func hideTabBarWithAnimation() -> () {
    UIView.transition(with: tableView, duration: 1.0, options: .transitionCrossDissolve, animations: { () -> Void in
        self.tabBarController?.tabBar.isHidden = true
    }, completion: nil)
}

Upvotes: -1

David_2877
David_2877

Reputation: 327

So I've been playing around for 3 days with this now, finding out that the one that worked for me in my code was Adriana's post from 14th Sept 2018. But I was not sure how to use the coding once copied into my Project. So, after much experimenting I found that the way I could use this func was to put the following into into the respective swipe actions.

setTabBarHidden(false)


setTabBarHidden(true)

My next step is to try to get the swipe actions working while using UIScrollView in the same UIView at the same time.

Upvotes: -1

Jakub Marek
Jakub Marek

Reputation: 194

Swift 4 solution:

tabBarController?.tabBar.isHidden = true
UIView.transition(with: tabBarController!.view, duration: 0.35, options: .transitionCrossDissolve, animations: nil)

Upvotes: 1

Adriana
Adriana

Reputation: 235

Improvement of the response of @Luca Davanzo. If the bar is already hidden, it will continue hiding it and moving it lower. Also get rid of the return, so the state of the tabbar.hidden changes when the animation happens. So I added a check:

extension UIViewController {

func setTabBarHidden(_ hidden: Bool, animated: Bool = true, duration: TimeInterval = 0.5) {
    if self.tabBarController?.tabBar.isHidden != hidden{
        if animated {
            //Show the tabbar before the animation in case it has to appear
            if (self.tabBarController?.tabBar.isHidden)!{
                self.tabBarController?.tabBar.isHidden = hidden
            }
            if let frame = self.tabBarController?.tabBar.frame {
                let factor: CGFloat = hidden ? 1 : -1
                let y = frame.origin.y + (frame.size.height * factor)
                UIView.animate(withDuration: duration, animations: {
                    self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: y, width: frame.width, height: frame.height)
                }) { (bool) in
                    //hide the tabbar after the animation in case ti has to be hidden
                    if (!(self.tabBarController?.tabBar.isHidden)!){
                        self.tabBarController?.tabBar.isHidden = hidden
                    }
                }
            }
        }
    }
}

}

Upvotes: 5

Luca Davanzo
Luca Davanzo

Reputation: 21520

I've developed a util extension for UIViewController
Swift 4 compatible:

extension UIViewController {

    func setTabBarHidden(_ hidden: Bool, animated: Bool = true, duration: TimeInterval = 0.3) {
        if animated {
            if let frame = self.tabBarController?.tabBar.frame {
                let factor: CGFloat = hidden ? 1 : -1
                let y = frame.origin.y + (frame.size.height * factor)
                UIView.animate(withDuration: duration, animations: {
                    self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: y, width: frame.width, height: frame.height)
                })
                return
            }
        }
        self.tabBarController?.tabBar.isHidden = hidden
    }

}

Upvotes: 12

Bogdan Novikov
Bogdan Novikov

Reputation: 595

In case if you need to toggle it from hide to visible and vice versa:

func toggleTabbar() {
    guard var frame = tabBarController?.tabBar.frame else { return }
    let hidden = frame.origin.y == view.frame.size.height
    frame.origin.y = hidden ? view.frame.size.height - frame.size.height : view.frame.size.height
    UIView.animate(withDuration: 0.3) {
        self.tabBarController?.tabBar.frame = frame
    }
}

Upvotes: 2

Samantha
Samantha

Reputation: 2289

You could change the tab bar's frame inside an animation, so something like:

func hideTabBar() {
    var frame = self.tabBarController?.tabBar.frame
    frame?.origin.y = self.view.frame.size.height + (frame?.size.height)!
    UIView.animate(withDuration: 0.5, animations: {
        self.tabBarController?.tabBar.frame = frame!
    })
}

func showTabBar() {
    var frame = self.tabBarController?.tabBar.frame
    frame?.origin.y = self.view.frame.size.height - (frame?.size.height)!
    UIView.animate(withDuration: 0.5, animations: {
        self.tabBarController?.tabBar.frame = frame!
    })
}

Which sets the tab bar just below the visible screen, so that it slides up/down from the bottom.

Upvotes: 12

Related Questions