6

I have an App using a Tabbar for basic Navigation. From one of the screens of the Tabbar I want to enter another one that shows a toolbar instead of the Tabbar and a back navigation item on the top.

What is the best way to do this? If I use "Hide Bottom Bar on Push" (aka hidesBottomBarWhenPushed) and add a Toolbar to the screen I can see an animation removing the Tabbar before the Toolbar is placed at the bottom of the screen.

Greg
  • 9,068
  • 6
  • 49
  • 91
Thomas Einwaller
  • 8,873
  • 4
  • 40
  • 55

6 Answers6

4

Problem Example

enter image description here

Here is my solution,

In the first view controller that has the tabbar do this

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "someSegue" {
        if let secondVC = segue.destinationViewController as? InfoTableViewController {
            secondVC.hidesBottomBarWhenPushed = true
        }
    }
}

I also needed this, as my toolbar would re appear in the first VC.

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    navigationController?.toolbarHidden = true
}

To stop the fade up animation of the toolbar, so its just there i used this in the second VC

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.toolbarHidden = false
}
DogCoffee
  • 19,820
  • 10
  • 87
  • 120
4

Solution for UITableViewController with toolbar (requires code)

Using code from this answer, I was able to achieve the same effect, but with the toolbar at the bottom of a table view.

Add this to your table view controller:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.navigationController setToolbarHidden:NO animated:YES];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.navigationController setToolbarHidden:YES animated:YES];
}

Important note: placing these calls in viewWillAppear and viewWillDisappear instead of viewDidLoad makes this easier to handle, as it will work reliably even for multiple pushes and pops of the same view controller, and you won't have to clean up after it in the previous view controller.

And configure it like this in the storyboard:

Also, enable Hides bottom bar when pushed in the storyboard, or in your code, for the view controller being pushed.

Then you can add toolbar buttons to the toolbar in the storyboard.

Build and run, and you get this effect:

enter image description here

Here's a complete sample project demonstrating this.

Community
  • 1
  • 1
Greg
  • 9,068
  • 6
  • 49
  • 91
  • I tried this but not working with my app, still getting the animation of the toolbar up on the second VC. – DogCoffee May 17 '15 at 06:32
  • @DogCoffee try looking at the sample project and comparing the settings. I created it from the default template and only changed the things listed here. – Greg May 17 '15 at 07:38
  • What are you using to create your GIF's ? My created GIFs aint great. – DogCoffee May 17 '15 at 08:10
  • I did it like that, the only difference is that I chose to use self.navigationController?.setToolbarHidden(false, animated: false) to avoid showing the animation to the user – Thomas Einwaller May 17 '15 at 21:28
  • Still an issue on 10.2 Xcode 8.2.1. Only seems to happen with Swift projects for me. This is the only solution still working, most of the other solutions fail to have any effect or solve the problem. – psobko Apr 11 '17 at 03:22
2

Pure storyboard solution

If you're referring to the issue of the toolbar appearing above the tab bar during the push transition animation, I was able to fix this by adjusting the auto layout constraints on the toolbar in the storyboard (add it manually to your view controller; see my other answer if you're using a UITableViewController or UICollectionViewController and can't do this):

Add a constraint to set the distance to the bottom layout guide to zero:

Double click that constraint to edit it, and set the first item to Bottom (it will be Top by default).

All done! This will result in an effect like this:

Here's my sample project that demonstrates this working as expected. Note that I didn't change any of the code, everything is in the storyboard.

Greg
  • 9,068
  • 6
  • 49
  • 91
  • I have seen this answer, but if you use a UITableViewController, you cannot add constraints to the toolBar (when you show it in interface builder)... well I couldnt anyway. – DogCoffee May 17 '15 at 04:56
  • @DogCoffee I couldn't find a way to do this with constraints either, but it's still doable, similarly to your answer, but avoiding cleanup in the source view controller (see my second answer). – Greg May 17 '15 at 05:11
  • I posted my first answer (and will leave it separate) because the question doesn't mention a table view being used, and is tagged `storyboard`, so I think a storyboard solution could be more convenient for the asker than the alternate one. – Greg May 17 '15 at 05:22
  • 2
    Xcode 7 doesn't allow you to change Top to Bottom for Bottom Layout Guide anymore. – Mojo66 Sep 23 '15 at 22:54
0

As of Xcode 7, the pure Storyboard solution doesn't work anymore because Xcode wouldn't let you assign the Bottom attribute to the Bottom Layout Guide anymore.

For my project, I used the following setup:

  • A UITabBarController as initial view controller, going into a
  • UINavigationController, with root vc set to...
  • UIRegularViewController, which should behave normally, but spawn a...
  • UISpecialViewController, which should hide the tab bar and instead display a toolbar. Also, it should hide the status bar, the navigation bar and the tool bar on tap.

Here is what I did to achieve this:

In the storyboard

UITabBarController: set Tab Bar Translucency to NO

UISpecialViewController: Set Simulated Metrics like so

  • Status Bar: None
  • Top Bar: Opaque Nav Bar
  • Bottom Bar: Opaque Toolbar

Set Extended Edges like this:

  • Under Top Bars: NO
  • Under Bottom Bars: YES
  • Under Opaque Bars: YES

Do not drag a UIToolBar into UISpecialViewController !

In the Implementations

// in UISpecialViewController.m
- (void)viewWillAppear:(BOOL)animated {
    self.navigationController.toolbarHidden = NO;
    self.navigationController.hidesBarsOnTap = YES;
}

- (void)viewWillDisappear:(BOOL)animated {

    self.navigationController.toolbarHidden = YES;
    self.navigationController.hidesBarsOnTap = NO;
}

- (BOOL)prefersStatusBarHidden {
    return self.navigationController.navigationBarHidden;
}

Here is the Demo Code.

This is the result:

enter image description here

Mojo66
  • 1,109
  • 12
  • 21
0

In fact, UIKit has already configured how Toolbar and Tabbar change in the page switching animation.

I also have this situation with you today, and the final solution surprised me.

For example, page A to page B, page A displays Tabbar, not Toolbar, page B does not display Toolbar, and does not display Tabbar.

At this time, B needs to set hidesBottomBarWhenPushed to true, which is necessary.

Then, in the declaration cycle of the two ViewControllers, in the viewWillDisappear of A and the viewWillAppear of B, if you set the navigation controller setToolbarHidden, this animation problem will occur.

If you set it in viewDidDisappear of A and viewDidAppear of B, the problem is solved. Although the toolbar will have a delayed animation, it is always better than the wrong animation.

Finally add: The order of A and B life cycle function calls is:

  1. A - viewWillDisappear
  2. B - viewWillAppear
  3. A - viewDidDisappear
  4. B - viewDidAppear

These four methods are interleaved.

0

Using Xcode 12.4 iOS 14.4

for those who struggle with this issue and try solutions above with no luck.

let's say A is with tabBar only, B is only showing toolbar

remember to set hidesBottomBarWhenPushed = true in B's init

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    hidesBottomBarWhenPushed = true
}

implement these below in B. (no need to do anything in A)

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.setToolbarHidden(true, animated: false)
}
override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    navigationController?.setToolbarHidden(false, animated: false)
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.setToolbarHidden(true, animated: true)
}

that's it!!

p.s. if you want to remove the toolbar animation from bottom up then add this

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    navigationController?.toolbar.layer.removeAnimation(forKey: "position")
}
andrew54068
  • 1,326
  • 14
  • 29