Swift UITabBarController hide with animation
Asked Answered
Q

9

8

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.

Quaver answered 15/12, 2016 at 17:24 Comment(0)
M
12

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.

Mallorie answered 15/12, 2016 at 17:36 Comment(0)
N
12

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
    }

}
Neese answered 3/5, 2018 at 15:32 Comment(4)
on iPhone X , when tab bar is hidden there is a gray background of tab bar there.Beker
@Alfi same here, did you fixed it?Heliopolis
@Mark Dylan B Mercado, Sure I fixed it but I don't remember how, Sorry I does't have access to that project right now to help you more.Beker
This solution is not save if you can call hidden=true when it's already hidden. It will move the frame endlessly down.Careerism
P
5

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
                    }
                }
            }
        }
    }
}

}

Patronize answered 14/9, 2018 at 9:46 Comment(0)
B
2

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
    }
}
Brunson answered 13/12, 2017 at 14:19 Comment(0)
B
1

Swift 4 solution:

tabBarController?.tabBar.isHidden = true
UIView.transition(with: tabBarController!.view, duration: 0.35, options: .transitionCrossDissolve, animations: nil)
Biron answered 13/11, 2018 at 15:32 Comment(0)
O
1

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

        })
    }
}
Overcoat answered 27/5, 2020 at 21:16 Comment(1)
Nice solution. But when calling hidden = false when tab is not hidden, it makes jumpy animationCareerism
C
0

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.

Crissycrist answered 22/8, 2023 at 9:30 Comment(0)
G
-1

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)
}
Gurnard answered 15/12, 2016 at 17:29 Comment(2)
It's not Swift 3 compliant. "hidden" doesn't exist anymore.Skeet
fixed to swift 3Gurnard
N
-1

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.

Notus answered 12/2, 2020 at 0:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.