How do you really hide and show a tab bar when tapping on part of your view? (no buttons but any location of the screen)

1.8k Views Asked by At
override func viewDidLoad() {        

    let tap = UITapGestureRecognizer(target: self, action: #selector(touchHandled))
    view.addGestureRecognizer(tap)


}


@objc func touchHandled() {
    tabBarController?.hideTabBarAnimated(hide: true)
}


extension UITabBarController {
    func hideTabBarAnimated(hide:Bool) {
        UIView.animate(withDuration: 2, animations: {
            if hide {
                self.tabBar.transform = CGAffineTransform(translationX: 0, y: 100)
            } else {
                self.tabBar.transform = CGAffineTransform(translationX: 0, y: -100)
            }
        })
    }

}

I can only hide the tab bar but I can't make it show when you tap again. I tried to look for answers on stack overflow but the answers seems to only work if you're using a button or a storyboard.

3

There are 3 best solutions below

1
Rakesha Shastri On BEST ANSWER

Have a variable isTabBarHidden in class which stores if the tabBar has been animated to hide. (You could have used tabBar.isHidden, but that would complicate the logic a little bit when animate hiding and showing)

class ViewController {

    var isTabBarHidden = false // set the default value as required

    override func viewDidLoad() {        
        super.viewDidLoad()

        let tap = UITapGestureRecognizer(target: self, action: #selector(touchHandled))
        view.addGestureRecognizer(tap)
    }

    @objc func touchHandled() {
        guard let tabBarControllerFound = tabBarController else {
            return
        }
        tabBarController?.hideTabBarAnimated(hide: !isTabBarHidden)
        isTabBarHidden = !isTabBarHidden
    }

}
1
Prashant Tukadiya On

Generalised solution with protocol which will work in all the screens

Create UIViewController named BaseViewController and make it base class of all of your view controllers

Now Define protocol

protocol ProtocolHideTabbar:class {
    func hideTabbar ()

}
protocol ProtocolShowTabbar:class {
    func showTabbar ()

}

extension ProtocolHideTabbar  where Self : UIViewController {
    func hideTabbar () {
        self.tabBarController?.tabBar.isHidden = true
    }
}
extension ProtocolShowTabbar  where Self : UIViewController {
    func showTabbar () {
        self.tabBarController?.tabBar.isHidden = false
    }
}

By default we want show tabbar in every view controller so

extension UIViewController : ProtocolShowTabbar {}

In your BaseView Controller

in view will appear method add following code to show hide based on protocol

    if self is ProtocolHideTabbar {
        ( self as! ProtocolHideTabbar).hideTabbar()
    } else  if  self is ProtocolShowTabbar{
        ( self as ProtocolShowTabbar).showTabbar()

    }

How to use

Simply

class YourViewControllerWithTabBarHidden:BaseViewController,ProtocolHideTabbar {
}

Hope it is helpful

0
Prashant Tukadiya On

Tested 100% working

Please try below code for that in UITabBarController subclass

 var isTabBarHidden:Bool = false


 func setTabBarHidden(_ tabBarHidden: Bool, animated: Bool,completion:((Void) -> Void)? = nil) {
        if tabBarHidden == isTabBarHidden   {

            self.view.setNeedsDisplay()
            self.view.layoutIfNeeded()

            //check tab bar is visible and view and window height is same then it should be 49 + window Heigth

            if (tabBarHidden == true && UIScreen.main.bounds.height == self.view.frame.height) {
                let offset = self.tabBar.frame.size.height
                self.view.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:self.view.frame.height + offset)

            }

            if let block = completion {

                block()
            }
            return
        }
        let offset: CGFloat? = tabBarHidden ? self.tabBar.frame.size.height : -self.tabBar.frame.size.height
        UIView.animate(withDuration: animated ? 0.250 : 0.0, delay: 0.1, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: [.curveEaseIn, .layoutSubviews], animations: {() -> Void in
            self.tabBar.center = CGPoint(x: CGFloat(self.tabBar.center.x), y: CGFloat(self.tabBar.center.y + offset!))

            //Check if View is already at bottom so we don't want to move view more up (it will show black screen on bottom ) Scnario : When  present mail app
            if (Int(offset!) <= 0 && UIScreen.main.bounds.height ==   self.view.frame.height) == false {
                self.view.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:self.view.frame.height + offset!)
            }
            self.view.setNeedsDisplay()
            self.view.layoutIfNeeded()

        }, completion: { _ in
            if let block = completion {
                block()
            }
        })
        isTabBarHidden = tabBarHidden
    }

Hope it is helpful