0

I'm using a very simple setup with a programmatically instantiated UITabBarController.

The configuration of my app comes from a server, and based on that config the viewControllers property is set on the fly. This means the number of viewControllers (and therefore the tabs) can change at any time.

This all works perfectly, except for one thing.

I would like to hide the tabBar when the UITabBarController only has 1 viewController in the viewControllers array.

I know you can set a flag on a viewController for newly pushed viewControllers to hide the bottom bar, but that's not what I'm looking for.

I want to programmatically control the visibility of the tabBar and obviously also set all the correct safe margings so that child viewController(s) get all the possible space.

Gertjan.com
  • 410
  • 1
  • 3
  • 12
  • Obviously :) but that doesn't solve the autolayout/safe margins/traitcollection etc. issues, it just leaves an empty space. – Gertjan.com Aug 31 '18 at 12:25

2 Answers2

1

I have come across such a scenario and I used the below code which worked for me successfully:

extension UITabBarController {
    func setTabBarVisible(visible:Bool, duration: TimeInterval = 0.20, animated:Bool) {
        if (tabBarIsVisible() == visible) { return }
        let frame = self.tabBar.frame
        let height = frame.size.height
        let offsetY = (visible ? -height : height)
        let duration = animated ? duration : 0
        var safeAreaInset:CGFloat = 0
        if #available(iOS 11, *) {
            safeAreaInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
            safeAreaInset += visible ? (UIApplication.shared.keyWindow?.safeAreaInsets.top ?? 0) : 0
        }

        if !visible, let window = self.view.window {
            if let view = window.viewWithTag(999) {
                view.removeFromSuperview()
            }
            let view = UIView()
            view.translatesAutoresizingMaskIntoConstraints = false
            window.insertSubview(view, at: 0)
            view.tag = 999
            view.leadingAnchor.constraint(equalTo: window.leadingAnchor).isActive = true
            view.trailingAnchor.constraint(equalTo: window.trailingAnchor).isActive = true
            view.bottomAnchor.constraint(equalTo: window.bottomAnchor).isActive = true
            view.heightAnchor.constraint(equalToConstant: safeAreaInset).isActive = true
            view.backgroundColor = .white
            window.sendSubview(toBack: view)
        }
        let viewFrame = CGRect(x:self.view.frame.origin.x,y:self.view.frame.origin.y,width: self.view.frame.width, height: (self.view.frame.height + offsetY - safeAreaInset))

        // animation
        UIView.animate(withDuration: duration, animations: {
            self.tabBar.frame.offsetBy(dx:0, dy:offsetY)
            self.view.frame = viewFrame
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
        }) { (finished) in
            if finished {
                if let view = self.view.window?.viewWithTag(999) {
                    self.view.window?.sendSubview(toBack: view)
                }
            }
        }

    }

    func tabBarIsVisible() ->Bool {
        return self.tabBar.frame.origin.y < UIScreen.main.bounds.height
    }
}

You can use it like this:

Have a local variable which will store the visibility status and also update the tabbar when set:

var tabbarHidden = false {
    didSet {
        self.tabbarController.setTabBarVisible(visible: !tabbarHidden, animated: false)
        self.tabbarController.tabBar.isHidden = tabbarHidden
    }
}

Have a function to set the visibility of the tabbar:

func setTabbarVisibility() {
    if !((self.tabbarController.selectedViewController as? UINavigationController)?.topViewController?.hidesBottomBarWhenPushed ?? false) {
        let count = Globals.sharedInstance.currentEvent?.bottom.count ?? 0
        self.tabbarHidden = count == 0
    }
}

Call this function in viewWillAppear and viewDidLayoutSubviews to update it as the setting is from server.

hardik parmar
  • 853
  • 8
  • 15
0

Write below code in your CustomTabBarViewController.

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    hideTabBar() //Calling function to hide tabbar
}

//Call below function when you want hide tabbar
func hideTabBar() {
    guard let firstViewController = self.viewControllers?.first as? TableListViewController else {
        return
    }

    DispatchQueue.main.async {
        self.tabBar.isHidden = true
        firstViewController.view.frame.size.height = UIScreen.main.bounds.size.height
    }
}

//Call below function when you want unhide tabbar
func unHideTabBar() {
     guard let firstViewController = self.viewControllers?.first as? TableListViewController else {
        return
    }

    DispatchQueue.main.async {
        self.tabBar.isHidden = false
        firstViewController.view.frame.size.height = UIScreen.main.bounds.size.height - self.tabBar.frame.size.height
    }
}

Hope this helps you!

Sunil Prajapati
  • 473
  • 5
  • 17