If I have a UITabBarController and do this inside one of its view controllers:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tabBarController?.tabBar.isUserInteractionEnabled = false
}
the first time it shows, I can still change tabs.
If I tap on another tab and tap back on the first tab, then the tabbar is really disabled, but not the first time.
Why? And how do I solve this?
EDIT:
There is one detail I noticed, the tabBarController?.tabBar.isUserInteractionEnabled = false has to be on the second view controller of a navigation controller. In other words:
Say I have that structure
UITabBarController
UINavigationController
UIViewController (1)
UIViewController (2)
UIViewController (3)
So if I add that viewDidAppear code on view controller (2), you can change the tab once, but not the second time (after you navigate to it, obviously).
And there is more, if I go back after navigating to view controller (2), the tab bar becomes "interactable" again, without my setting it to true.
Having a tab bar in view, but not being able to interact with it will probably be confusing and frustrating for the user. And while I don't have the reason or solution for the original question, I have an alternative suggestion:
Hide the tab bar in UIViewController (2):
override func viewDidLoad() {
super.viewDidLoad()
tabBarController?.tabBar.isHidden = true
}
We're putting this in viewDidLoad so it's hidden as soon as the view
appears.
This also requires that you explicitly unhide it in UIViewController (1) for when the user hits the back button. Do it in viewWillAppear since the view was loaded already and we're going back to it.
override func viewWillAppear(_ animated: Bool) {
tabBarController?.tabBar.isHidden = false
}
While I have experienced the same behavior with:
tabBarController?.tabBar.isUserInteractionEnabled = false
..what you CAN do is disable each of the items in the tabBar.items collection, and then re-enable them in the viewWillAppear method of another controller. For example, if you didn't want your users tabbing out of menu #1 once they are inside it, you could do something like this in the subsequent controller(s):
override func viewWillAppear(_ animated: Bool) {
//0th tab items remains enabled as "only choice" for user
self.tabBarController!.tabBar.items![1].isEnabled = false
self.tabBarController!.tabBar.items![2].isEnabled = false
self.tabBarController!.tabBar.items![3].isEnabled = false
self.tabBarController!.tabBar.items![4].isEnabled = false
}
when the user tabs back to first tab (0) (or hits the back button), in that viewController's viewWillAppear method, re-enable the items:
override func viewWillAppear(_ animated: Bool) {
//re-enable tab items
self.tabBarController!.tabBar.items![1].isEnabled = true
self.tabBarController!.tabBar.items![2].isEnabled = true
self.tabBarController!.tabBar.items![3].isEnabled = true
self.tabBarController!.tabBar.items![4].isEnabled = true
}
Related
The sequence is tabBarController->navigationController->viewController->viewController
I wrote the following code in the second viewController.
When the user comes to the second viewController, I want to hide the tab bar.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tabBarController?.tabBar.isHidden = true
}
When the user clicks "Cancel" button, I want to go back to the main page.
#IBAction func cancelAction(_ sender: Any) {
// Depending on style of presentation (modal or push presentation), this view controller needs to be dismissed in two different ways.
self.navigationController?.popToRootViewController(animated: true)
}
After go back to the first viewController, I want to make the tab bar show again.
override func viewWillAppear(_ animated: Bool) {
self.tabBarController?.tabBar.isHidden = false
}
But in fact, the tab doesn't show at all. And the page suddenly shakes for a moment. Don't know why.
Remove all your code for setting Tab bar, and try this option for Second View Controller in XIB or Storyboard:
I have a View Controller which is the 2nd View Controller and need a navigation bar. The 1st one is a controller which doesn't need a Nav Bar and 3rd View Controller need a navigation bar.
As per stacks 3rd view controller will be no top of stack.
I have implemented these methods in 2nd View Controller:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if self.navigationController?.navigationBarHidden == true{
self.navigationController?.navigationBarHidden = false
}
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
self.navigationController?.navigationBar.tintColor = Quikr_Util.colorWithHexString("#0083cb")
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if self.navigationController?.navigationBarHidden == false{
self.navigationController?.navigationBarHidden = true
}
}
The things were working fine if a use a back bar button to go back from 3rd to 2nd View Controller.
Things got messy when I started to slide from one View Controller to another for example, when I slide half and then release.
It means sliding from 3rd to 2nd but release in between so it goes to 3rd View Controller rather than second .
What may be the best way to hide and unhide view navigation bars .
Secondly, how do sliding works , which functions will get called when sliding happens?
For your first question
To hide and show the Navigation Controller, in 2nd and 3rd View Controllers, You can use:
Hide:
navigationController?.setNavigationBarHidden(true, animated: false)
Show:
navigationController?.setNavigationBarHidden(false, animated: false)
There is not really a need to check if it is hidden or not.
For the second question, you can use UIGestureRecognizer
Edit:
Just to be clear, instead of hiding and showing the in the same file, hide and show in viewDidAppear() in needed swift files
I have a parent TableViewController and a child ViewController all within the context of a navigation controller. What I want to happen is for the table view controller to NEVER show the nav bar, and for the view controller to ALWAYS show the nav bar. I hide and show the nav bar within the viewWillAppear func of each subclass, like this:
table view controller:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true);
navigationController?.navigationBar.hidden = true
UIApplication.sharedApplication().statusBarHidden=true
}
view controller:
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
}
This works for the first navigation. When I launch the app, the parent table view controller hides the nav bar, and when I select the first cell, the child view controller dutifully displays the nav bar. However, when I touch 'Back' on the nav bar, and then select the cell again, the view controller is no longer displaying the nav bar.
Is there a better way to do this?
Update - as requested attaching screenshots of XIB and Storyboard. Note that there is no XIB for the parent TableViewController. I am not confident that these screenshot will provide much insight. Especially that of the storyboard. Unfortunately, Xcode only has 2 zoom levels:
1. Too zoomed in to be useful
2. Too zoomed out to be useful
Nonetheless, here you have them:
That should work fine: When your ViewController will appear, the code should get executed every time. Try with an "print" to test if that happens.
First View Controller
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
print("viewWillLoad - Table View")
self.navigationController?.navigationBarHidden = false
}
Second View Controller
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
print("viewWillLoad - Detail View")
self.navigationController?.navigationBarHidden = true
}
Ill use that in some applications too.
I have the hidesBottomBarWhenPushed = true set for one of my UIViewController's (call it ViewControllerA) that is pushed onto my UINavigationController stack. I also opt to show the bottomBar when I push a new ViewController ontop of ViewControllerA. Therefore I have:
class ViewControllerA: UIViewController {
override func viewWillDisappear(animated: Bool) {
self.hidesBottomBarWhenPushed = false
}
override func viewWillAppear(animated: Bool) {
self.hidesBottomBarWhenPushed = true
}
This all works fine.
When I push ViewControllerA, the bottom bar hides.
When I push any other ViewController, the bottom bar shows.
However, when I am traveling backwards in the navigation stack (aka hitting the UIBarButtonItemBack button), I cannot get the bottomBar to hide when I pop the navigation stack to reveal ViewControllerA.
What am I missing? Thanks!
Got it! Here's what worked:
class ViewControllerCustom: UIViewController {
init() {
self.hidesBottomBarWhenPushed = true
}
override func viewDidAppear(animated: Bool) {
self.hidesBottomBarWhenPushed = false
}
}
And then in every UIViewController's custom implementation of BarButtonItemBack pressed I check to see if the previous view controller (that will be popped to needs to hide the tab bar). Granted I abstracted this out into a general function so I didn't need to repeat code, but here's the concept. Thanks for the help figuring this out though!
func barButtonItemBackPressed(button: UIButton) {
var viewControllers = self.navigationController!.viewControllers as! [UIViewController]
if ((viewControllers[viewControllers.count - 2]).isKindOfClass(ViewControllerCustom.self)) {
(viewControllers[viewControllers.count - 2] as! ViewControllerCustom).hidesBottomBarWhenPushed = true
}
self.navigationController?.popViewControllerAnimated(true)
}
I believe the intended use of this property is to hide the bar when pushed. So, when your view controller appears after the top-most one is popped, it wasn't pushed on the stack, so it doesn't change the tab bar's appearance.
This leaves you with two options:
1) Keep the bottom bar for all view controllers. When text is being entered, the keyboard covers the bottom bar.
2) Hide the bottom bar for View Controller A, as well as any other view controller that is pushed on top of A.
I'm addapting this code in my project https://github.com/stuartbreckenridge/UISearchControllerWithSwift
After Navigation Controller and before Countries Scene (ViewController) I have put one more View Controller, so now in Countries View controller I have back button. After inputing something in search bar when I press Back, search bar still is visible.
I've tried hide it doing this (countrySearchController is UISearchController):
override func viewWillDisappear(animated: Bool) {
self.countrySearchController.active = false
}
But it hides UISearchController with delay, so it's stil visible for half a second.
Input something:
And then press back:
Correct way probably is to set self.definesPresentationContext in viewDidLoad
self.definesPresentationContext = true
That caused some glitches when UISearchController became active, so I just removed the searchBar from Superview.
override func viewWillDisappear(animated: Bool) {
searchController.searchBar.removeFromSuperview()
searchController.active = false;
super.viewWillDisappear(true)
}