How to hide parent tabbar when pushing controller in navigationController - ios

I have an application with a tab bar controller and each view contains a navigation controller. My MainWindow looks as follows: Image here http://www.freeimagehosting.net/image.php?7bc867a594.png
Everything works fine as it is but I noticed a problem when pushing a details view to the navigation controller. In the didSelectRowAtIndexPath for a tableviewcontroller that belongs to the tab bar controller (the one called Latest in the image) I am doing this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ArticleViewController *articleController = [[ArticleViewController alloc] initWithNibName:#"ArticleView" bundle:nil];
[self.navigationController pushViewController:articleController animated:YES];
[articleController release];
articleController = nil;
}
The ArticleViewController has its own tabbar because it needs to display different things. The problem is that when I push the ArticleViewController into the navigationController I see both tabbars at the bottom of the view. Is there any way I can solve this problem?
Thanks in advance

After spending hours and posting a question here I found that the solution to this problem is adding the following line after the instantiation of ArticleController.
articleController.hidesBottomBarWhenPushed = YES;

If you prefer storyboard configuration over coding there is a toggle for that. Just go destinationViewController > Attribute Inspector:

A very simple solution:
destinationViewController.hidesBottomBarWhenPushed = YES;
In your case:
articleController.hidesBottomBarWhenPushed = YES;
Hope this helps!

You can simple hide parent tabbar through storyboard .
Select viewcontroller > Attribute Inspector > check Hide Bottom Bar on Push

You can add below code in the view controller, which you are pushing.
-(BOOL)hidesBottomBarWhenPushed
{
return YES;
}
This will hide the tabbar in the pushed view controller only and as you pop the view controller tabbar remains unhide in rest all view controllers.
Swift version (3.x and above)
override var hidesBottomBarWhenPushed: Bool {
get {
return navigationController?.topViewController == self
}
set {
super.hidesBottomBarWhenPushed = newValue
}
}
Thanks

for swift 3,write the same code by you unhide the tabbar before pushviewController code like below
var frame = self.tabBarController?.tabBar.frame
frame?.origin.y = self.view.frame.size.height - (frame?.size.height)!+112
UIView.animate(withDuration: 0.2, animations: {
self.tabBarController?.tabBar.frame = frame!
})
self.navigationController?.pushViewController(viewController, animated: true)
or use just whant to unhide the tabbar u can use
viewController.hidesBottomBarWhenPushed = false

enter image description here
Go to interface builder in Xcode -> open attribute inspector and check the item 'Hide Bottom bar on Push' for view controller you don't want to show tab bar. It will work!!

Use property hidesBottomBarWhenPushed in the controller that you want to hide.
For hide, all controllers put into prepare for segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
segue.destination.hidesBottomBarWhenPushed = true
}

Related

UISplitViewController - dismiss / pop Detail View Controller in code in collapsed mode

Since iOS8 we're allowed to use UISplitViewController on both compact and regular devices. This is great because I don't have to create two different storyboard for iPhone and iPad, but there's one problem that I'm stuck with.
If the split view controller is on iPad(if the collapsed property is NO), I can simply call this to show MasterVC on the left side.
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;
[self.splitViewController.displayModeButtonItem action];
But if it's on iPhone(if the collapsed property is YES), the displayMode is ignored, and doesn't do anything.
I cannot pop DetailVC with popToRootViewControllerAnimated because DetailVC has it's own navigation controller.
How does Apple expect us to show MasterVC(dismiss DetailVC) in code in collapsed mode if there isn't any method like dismissViewControllerAnimated:completion: for view controller that was presented with showDetail? Your help will be appreciated. Thanks
On devices which don't support the "split" mode, if
You want to present the master view controller instead of the detail when the UISplitViewController first loads, then returning YES in your delegate class (UISplitViewControllerDelegate) splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: method method should do that:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
return YES;
}
You want to dismiss the detail view controller back to the master, after a specific event (e.g. a touch on a button). In this case you have to pop the detail view controller navigation controller:
[detailViewController.navigationController.navigationController popToRootViewControllerAnimated:YES]
Had a similar issue today trying to pop back from a detail view in a split view controller.
While I'm sure the accepted answer works fine, another approach I found that works as well and may be a bit cleaner is to use an unwind segue.
I setup an unwind segue on the master view I wanted to return to, then created a segue link to the unwind segue from the view I wanted to pop (note: assumes that you are using storyboards).
Make sure to setup the IBAction on the destination view you are popping back to:
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue { }
Connect the exit to the segue in the storyboard for the unwind segue. Sorry, I'm not providing a lot of detail on how to setup the unwind segue, but there are many tutorials available for that.
Then on your controller you want to dismiss, connect a segue to the unwind segue of the controller you are popping back to. Be sure to name the segue.
Then on the button touch in the view controller you want to dismiss, just call
[self performSegueWithIdentifier:#"unwindSegueName" sender:self];
This worked really well and avoids digging backwards into a navigation hierarchy that may change.
Hope this is useful to someone!
Happy Holidays!
Here's what I ended up doing to pop the DetailVC if we are in a collapsed state (iPhone excluding +sizes), and show/hide the MasterVC if we are not in a collapsed state (iPad).
#IBAction func backTouchUp(_ sender: UIButton) {
if let splitViewController = splitViewController,
!splitViewController.isCollapsed {
UIApplication.shared.sendAction(splitViewController.displayModeButtonItem.action!, to: splitViewController.displayModeButtonItem.target, from: nil, for: nil)
} else {
navigationController?.popViewController(animated: true)
}
}
Thanks pNre! Here's code that will handle displaying a custom back button when collapsed and the displayModeButton when not collapsed.
lazy var backButtonItem: UIBarButtonItem = {
UIBarButtonItem(image: UIImage(named: "backImage"), style: .plain, target: self, action: #selector(dismissAnimated))
}()
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
guard let svc = splitViewController else { return }
if svc.isCollapsed {
navigationItem.leftBarButtonItem = backButtonItem
} else {
navigationItem.leftBarButtonItem = svc.displayModeButtonItem
}
}
func dismissAnimated() {
_ = navigationController?.navigationController?.popViewController(animated: true)
}
I've placed this in willLayoutSubviews() instead of viewDidLoad() so that the button will be updated adaptively, e.g., for orientation changes on iPhone 7 Plus and size class changes such as while in split view on iPad.

Call popToRootViewControllerAnimated: on back button pressed

I have an UINavigationController in my iPhone app controlling views in a drill-down fashion. In the second last view I'd like to return to the root view by pressing the default back button. I know that the method popToRootViewControllerAnimated: does just that. But where do I place it?
One option is to use leftBarButtonItem rather than backBarButtonItem on self.navigationItem. i.e.
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(popToRootViewController:)];
Which would then call the selector popToRootViewController in your view controller, which could be implemented like so:
-(void)popToRootViewController:(id)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}
The issue that I see is that you won't have the native back button appearance.
Another option is to change the target and selector property on the backBarButtonItem.
[self.navigationItem.backBarButtonItem setTarget:yourTarget]
[self.navigationItem.backBarButtonItem setSelector:#selector(popToRootViewController:)]
Be aware that the backBarButtonItem should be set on the view controller in the stack that comes before the view controller where you would like the button to be visible:
self.navigationController.viewControllers
| ...
|
|-- SecondViewController <-- Set the backBarButtonItem here to be visible on LastViewController
|-- LastViewController
As far as I know, you can not pop to Root ViewController through the default back button because this default button is only for popping into the previous view Controller. So, if you want to pop back to the root ViewController, you can make make a custom bar button on the navigation bar and you can use popToRootViewControllerAnimated: in the selector method of this custom bar button. If you want to use only one back button for popping to root ViewController, you can simply hide your default back button by using this:
self.navigationItem.hidesBackButton = YES;
And then, you can add your custom back button on your navigation bar through which you can pop to root ViewController.
Please let me know if it works. Thanks :)
You can use viewWillDisappear
-(void) viewWillDisappear {
NSArray *viewControllers = self.navigationController.viewControllers;
if ([viewControllers indexOfObject:self] == NSNotFound) {
// View is disappearing because it was popped from the stack
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
Got some code from here: viewWillDisappear: Determine whether view controller is being popped or is showing a sub-view controller
This code will pop to the root view controller when the view is being popped (which happens when the back button is pressed).
You should subclass your UINavigationController and overwrite the method popViewControllerAnimated(animated: Bool).
override func popViewControllerAnimated(animated: Bool) -> UIViewController? {
guard let last = self.viewControllers.last else {
return nil
}
if last.isKindOfClass(MySecondLastViewController.self) {
return super.popToRootViewControllerAnimated(animated)![0]
} else {
if self.viewControllers.count >= 2 {
return super.popViewControllerAnimated(animated)
} else {
return nil
}
}
}

How to hide Tabbar in UITabbar Controller first 3 view Controller in ios7 [duplicate]

I have views with a navigation bar and a tab bar. What I would like to happen is to hide the tab bar on a certain view and show the tab bar again when the user changes views.
I saw a snippet of code for hiding the tab bar:
-(void)makeTabBarHidden:(BOOL)hide
{
// Custom code to hide TabBar
if ( [tabBarController.view.subviews count] < 2 ) {
return;
}
UIView *contentView;
if ( [[tabBarController.view.subviews objectAtIndex:0] isKindOfClass:[UITabBar class]] ) {
contentView = [tabBarController.view.subviews objectAtIndex:1];
} else {
contentView = [tabBarController.view.subviews objectAtIndex:0];
}
if (hide) {
contentView.frame = tabBarController.view.bounds;
}
else {
contentView.frame = CGRectMake(tabBarController.view.bounds.origin.x,
tabBarController.view.bounds.origin.y,
tabBarController.view.bounds.size.width,
tabBarController.view.bounds.size.height - tabBarController.tabBar.frame.size.height);
}
tabBarController.tabBar.hidden = hide;
}
from: http://nickwaynik.com/iphone/hide-tabbar-in-an-ios-app/
I call this on the view wherein I want the tab bar hidden
[self makeTabBarHidden:YES];
it works fine when i show/hide it on that view but when I navigate back to the previous view, the tab bar there is also hidden. I tried calling that function in the view's viewDidUnload, viewWillDisappear, viewDidDisappear functions but nothing happens. The same is true when the function is called in the previous view's viewDidLoad, viewWillAppear, viewDidAppear functions.
You can set the UIViewController.hidesBottomBarWhenPushed instead:
DetailViewController *detailViewController = [[DetailViewController alloc] init];
detailViewController.hidesBottomBarWhenPushed = YES;
[[self navigationController] pushViewController:detailViewController animated:YES];
[detailViewController release];
You can also do this in the Interface Builder for a storyboard. Select the View Controller that you want to hide the Tab Bar for and then select "Hide Bottom Bar on Push".
I just created a category on UITabBarController that allows you to hide the TabBar, optionally with an animation:
https://github.com/idevsoftware/Cocoa-Touch-Additions/tree/master/UITabBarController_setHidden
It adds the tabBarHidden property (with isTabBarHidden as its getter) and the - (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated method.
Swift 3:
Set tab bar to hide in viewWillAppear or viewDidAppear
self.tabBarController?.tabBar.isHidden = true
Try this for hide / show:
- (void)viewWillDisappear:(BOOL)animated {
self.hidesBottomBarWhenPushed = NO;
}
- (void)viewWillAppear:(BOOL)animated {
self.hidesBottomBarWhenPushed = YES;
}
self.navigationController.hidesBottomBarWhenPushed=YES;
Add this line to your viewDidLoad or viewWillAppear; this will hide you tab from bottom.
The same property is available on the attributes inspector when you click on your view controller on your Xib or storyboard file.
you can use below code but tabBar remains hidden when you navigate back.
//hide tabbar
//self.tabBarController?.tabBar.isHidden = true
better way is to do through main.storyboard
check "Hide Bottom Bar on Push" as I've done.

How to hide the tabBar when push a view?

My application is a Tabbed Application, and it have several controllers under the tabBarController. One controller is a navigationController, and its root view is a table view. When I click a row of the table view, another view will be pushed in.
So the question is that when the view is pushed in, how can I hide the tabBar at the bottom?
Besides, I also want to add another tabBar into the pushed view, so I need to alloc a UITabBar or UITabBarController? Or there is another way? Thank you!
use this methood in the UIViewController class where you want to hide the tabBarController
-(BOOL)hidesBottomBarWhenPushed
{
return YES;
}
Update
As suggested by #Yuchen Zhong in his answer, This option is now available in the storyboard itself.
You can do this in storyboard now:
Select the UIViewController in your storyboard
Select the checkbox Hide Bottom Bar on Push
Set UIViewController.hidesBottomBarWhenPushed = YES when you want hide tab bar.
nextViewController.hidesBottomBarWhenPushed = YES;
Sometimes the hidesBottomBarWhenPushed method hides the bottom bar with a choppy animation.
Instead I hide the tabbar in viewDidLoad with
self.tabBarController.tabBar.hidden = YES;
and restore its presence in viewWillDisappear
self.tabBarController.tabBar.hidden = NO;
Set true hidesBottomBarWhenPushed in the controller that you want to hide.
For hide all controllers put into prepare for segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
segue.destination.hidesBottomBarWhenPushed = true
}

Hide TabBar when pushed into the navigation stack and bring it back when popped out of the navigation stack

I am trying to do the following.
I have a tab bar controller with 2 tabs in it. Both the tabs are navigation controller with a table view on each of them.
Now when I select one cell of the table in the first tab, I am pushing another tab bar controller, so I would like to hide the tab bar of the parent tabbarcontroller, and when I click the back button on the navigation bar I would like to see the the parent tab bar again, as I am in my parent tab bar view.
I tried hidesbottombarwhenpushed and it hides the parent tab bar controller tab bar but when I click back it doesn't brings it back.
Ok, So finally I got my answer, this is what I am suppose to do.
self.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:aViewController animated:YES];
self.hidesBottomBarWhenPushed=NO;
So basically hidesBottomBarWhenPushed = YES, and then push your view controller and then hidesBottomBarWhenPushed = NO; this works like a charm.
Thanks to eddy and his post here
The accepted answer had a problem to me.
My app had a navigation with the depth of three UIViewController.
The FirsViewController show's the UITabBar. (Correct)
The FirsViewController pushes the SecondViewController, and the SecondViewController don't show's the UITabBar. (Correct)
The SecondViewController pushed the ThirdViewController, and the ThirdViewController show's the UITabBar. (Incorrect)
The ThirdViewController popped to the SecondViewController, and the SecondViewController show's the UITabBar. (Incorrect)
The SecondViewController popped to the FirstViewController, and the FirstViewController show's the UITabBar. (Correct)
The solution for me was setting the delegate of UINavigationControllerDelegate
swift:
self.navigationController?.delegate = self
Objective-c:
self.navigationController.delegate = self;
And then implement the following delegate method
Swift:
fun navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if fromVC.isKindOfClass(FirstViewController) && toVC.isKindOfClass(SecondViewController) {
self.hidesBottomBarWhenPushed = true;
}
else if fromVC.isKindOfClass(SecondViewController) && toVC.isKindOfClass(FirstViewController) {
self.hidesBottomBarWhenPushed = false;
}
return nil
}
Objective-c:
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
{
if ([fromVC isKindOfClass:[FirstViewController class]] && [fromVC isKindOfClass:[SecondViewController class]]) {
self.hidesBottomBarWhenPushed = true;
}
else if ([fromVC isKindOfClass:[SecondViewController class]] && [fromVC isKindOfClass:[FirstViewController class]]) {
self.hidesBottomBarWhenPushed = false;
}
return nil;
}
Hope it helped.
As the Apple documentation states, you can't push a UITabBarController instance on a NavigationController. And there's a good reason for that: how do you get back from the pushed tab bar controller if you selected another item in the tab bar?
The simple answer is: don't do that, it will confuse your user. You can try swapping the first view controller for another view controller that may be a tab bar controller, but do not use the push paradigm for that: use an explicit button instead that will swap your first tab bar controller for the second one, preferably using a visual transition.
You can look at the setAnimationTransition:forView:cache: documentation for the UIView class to know how to swap, say, a tab bar controller for another:
Begin an animation block.
Set the transition on the container view.
Remove the subview from the container view.
Add the new subview to the container view.
Commit the animation block.
In this case, the container view will be the application's window.
You can also hide it using the attributes inspector when select the tabBar controller
Set hidesBottomBarWhenPushed = true in the controller that will be pushed.
For hide all controllers put into prepare for segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
segue.destination.hidesBottomBarWhenPushed = true
}
In your FirstViewController use
self.hidesBottomBarWhenPushed = true
in your SecondViewController use
override func willMoveToParentViewController(parent: UIViewController?) {
if parent == nil {
var viewControllers = self.navigationController!.viewControllers
if ((viewControllers[viewControllers.count - 2]).isKindOfClass(FirstViewController.self)) {
(viewControllers[viewControllers.count - 2] as! FirstViewController).hidesBottomBarWhenPushed = false
}
}
}

Resources