76

I have a problem with UITabBarController. In my application, I want to hide it but without using hidesBottomBarWhenPushed because I want to hide it not when I pushed it. For Example, I want to hide it when I press a Hide button in my application.

I read many articles in google but I cant find out how I can do this.

fabian789
  • 8,348
  • 4
  • 45
  • 91
Viktor Apoyan
  • 10,655
  • 22
  • 85
  • 147
  • possible duplicate of [Iphone: Is it possible to hide the TabBar?](http://stackoverflow.com/questions/1982172/iphone-is-it-possible-to-hide-the-tabbar) – Pang Mar 18 '14 at 09:14

16 Answers16

149

I am pasting this from my working code... you can call these methods to hide and show the tabbarcontroller.... just pass tabbarcontroller instance to these functions..

// Method call
[self hideTabBar:self.tabBarController];   

// Method implementations
- (void)hideTabBar:(UITabBarController *) tabbarcontroller
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];

    for(UIView *view in tabbarcontroller.view.subviews)
    {
        if([view isKindOfClass:[UITabBar class]])
        {
            [view setFrame:CGRectMake(view.frame.origin.x, 480, view.frame.size.width, view.frame.size.height)];
        } 
        else 
        {
            [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 480)];
        }
    }

    [UIView commitAnimations];   
}

- (void)showTabBar:(UITabBarController *) tabbarcontroller
{       
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    for(UIView *view in tabbarcontroller.view.subviews)
    {
        NSLog(@"%@", view);

        if([view isKindOfClass:[UITabBar class]])
        {
            [view setFrame:CGRectMake(view.frame.origin.x, 431, view.frame.size.width, view.frame.size.height)];

        } 
        else 
        {
            [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 431)];
        }
    }

    [UIView commitAnimations]; 
}
Saurabh
  • 22,743
  • 12
  • 84
  • 133
  • does apple allow you to do it? I mean, tabbar should be readonly.. just wondering if my app gonna be rejected – mateusmaso Feb 19 '12 at 05:14
  • 3
    i'm try for this solution. when call hideTabbar() method my tab bar is hide but it showing black space in bottom (position same tab bar). how i can fix this? – Thunderbird Aug 20 '14 at 05:31
58

Modified Setomidor's answer to work on both landscape, portrait, and iPad (the 320 and 480 values only work on iPhone).

- (void) hideTabBar:(UITabBarController *) tabbarcontroller 
{
    CGRect screenRect = [[UIScreen mainScreen] bounds];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    float fHeight = screenRect.size.height;
    if(  UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) )
    {
        fHeight = screenRect.size.width;
    }

    for(UIView *view in tabbarcontroller.view.subviews)
    {
        if([view isKindOfClass:[UITabBar class]])
        {
            [view setFrame:CGRectMake(view.frame.origin.x, fHeight, view.frame.size.width, view.frame.size.height)];
        } 
        else 
        {
            [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
            view.backgroundColor = [UIColor blackColor];
        }
    }
    [UIView commitAnimations];
}



- (void) showTabBar:(UITabBarController *) tabbarcontroller 
{   
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    float fHeight = screenRect.size.height - tabbarcontroller.tabBar.frame.size.height;

    if(  UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) )
    {
        fHeight = screenRect.size.width - tabbarcontroller.tabBar.frame.size.height;
    }

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    for(UIView *view in tabbarcontroller.view.subviews)
    {   
        if([view isKindOfClass:[UITabBar class]])
        {
            [view setFrame:CGRectMake(view.frame.origin.x, fHeight, view.frame.size.width, view.frame.size.height)];            
        } 
        else 
        {
            [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
        }       
    }
    [UIView commitAnimations]; 
}

Also modified the code to handle changes introduced in iOS 6 with UIDevice orientation change and ensure that it works properly even when the device is lying on its back.

karlbecker_com
  • 969
  • 1
  • 10
  • 16
  • 10
    You should replace `- 49.0` with `tabbarcontroller.tabBar.frame.size.height` for cleaner code that has a less chance of breaking in future iOS versions. – Ethan Allen Jun 15 '13 at 20:02
34

In your action method for the button:

[self.tabBarController.tabBar setHidden:YES];
Sailesh
  • 25,517
  • 4
  • 34
  • 47
12

Saurahb and karlbecker_com's solutions are great, though they can cause an obvious popping effect when the view contains a tableview while the tab bar animates back up. I've made some modifications and combined it into a single function (as a category on UITabBarController). It's not completely perfect (delayed correction animation) but gives good results with tables.

If you like animation blocks and categories, give this a try. Orientation and device friendly.

UITabBarController+ShowHideBar.m:

#import "UITabBarController+ShowHideBar.h"

@implementation UITabBarController (ShowHideBar)

- (void) setHidden:(BOOL)hidden{

    CGRect screenRect = [[UIScreen mainScreen] bounds];
    float fHeight = screenRect.size.height;
    if(  UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) ){
        fHeight = screenRect.size.width;
    }

    if(!hidden) fHeight -= self.tabBar.frame.size.height;

    [UIView animateWithDuration:0.25 animations:^{
        for(UIView *view in self.view.subviews){
            if([view isKindOfClass:[UITabBar class]]){
                [view setFrame:CGRectMake(view.frame.origin.x, fHeight, view.frame.size.width, view.frame.size.height)];
            }else{
                if(hidden) [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
            }
        }
    }completion:^(BOOL finished){
        if(!hidden){

            [UIView animateWithDuration:0.25 animations:^{

                for(UIView *view in self.view.subviews)
                {
                    if(![view isKindOfClass:[UITabBar class]])
                        [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
                }

            }];
        }
    }];

}

@end

UITabBarController+ShowHideBar.h:

#import <UIKit/UIKit.h>

@interface UITabBarController (ShowHideBar)

- (void) setHidden:(BOOL)hidden;

@end

Usage:

[self.tabBarController setHidden:YES];
[self.tabBarController setHidden:NO];
Thomas Verbeek
  • 2,361
  • 28
  • 30
9

Saurabh's answer above can be extended to also work in landscape orientation:

+ (void) hideTabBar:(UITabBarController *) tabbarcontroller {

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];

    //Support for landscape views
    int orientation = [[UIDevice currentDevice] orientation];
    int x_pos = 480;
    if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
        x_pos = 320;
    }

    for(UIView *view in tabbarcontroller.view.subviews)
    {
        if([view isKindOfClass:[UITabBar class]])
        {
            [view setFrame:CGRectMake(view.frame.origin.x, x_pos, view.frame.size.width, view.frame.size.height)];
        } 
        else 
        {
            [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, x_pos)];
        }       
    }   
    [UIView commitAnimations]; 
}

`

The corresponding x_pos numbers for showTabBar() are 431 and 271.

Setomidor
  • 954
  • 9
  • 15
4

This is karlbecker_com's answer, ported to MonoTouch (Xamarin.iOS). The only difference is that I implemented the methods on a class that inherits from UITabBarController, so references to "tabbarcontroller" were replaced by "this".

public void HideTabBar()
{
    var screenRect = UIScreen.MainScreen.Bounds;
    float fHeight = screenRect.Height;
    if(UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeLeft
       || UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeRight)
    {
        fHeight = screenRect.Width;
    }

    UIView.BeginAnimations(null);
    UIView.SetAnimationDuration(0.4);
    foreach(UIView view in this.View.Subviews)
    {
        if(view is UITabBar)
        {
            view.Frame = new RectangleF(view.Frame.X, fHeight, view.Frame.Width, view.Frame.Height);
        } 
        else 
        {
            view.Frame = new RectangleF(view.Frame.X, view.Frame.Y, view.Frame.Width, fHeight);
            view.BackgroundColor = UIColor.Black;
        }
    }
    UIView.CommitAnimations();
}

public void ShowTabBar()
{   
    var screenRect = UIScreen.MainScreen.Bounds;
    float fHeight = screenRect.Height - 49f;
    if(UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeLeft
       || UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeRight)
    {
        fHeight = screenRect.Width - 49f;
    }

    UIView.BeginAnimations(null);
    UIView.SetAnimationDuration(0.4);
    foreach(UIView view in this.View.Subviews)
    {
        if(view is UITabBar)
        {
            view.Frame = new RectangleF(view.Frame.X, fHeight, view.Frame.Width, view.Frame.Height);
        } 
        else 
        {
            view.Frame = new RectangleF(view.Frame.X, view.Frame.Y, view.Frame.Width, fHeight);
        }
    }
    UIView.CommitAnimations();
}
Diego
  • 18,035
  • 5
  • 62
  • 66
4

@karlbecker_com Answer works perfect for both the iPhone 4 and iPhone 5. If anyone is having issues with iOS7 black bar at the bottom set the tabBarController to translucent

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

// To Hide the black line in IOS7 only, this extra bit is required
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
    [self.tabBarController.tabBar setTranslucent:YES];
}  
mikemike396
  • 2,435
  • 1
  • 26
  • 41
4

in iOS8 it is enough to just set the hidden property of the tabBar
Like in Swift you can

rootTabVC = UITabBarController()
rootTabVC?.tabBar.hidden = true

I do this in my didFinishLaunchingWithOptions in the appdelegate and it works fine, I think if I remember correctly in the older iOS versions you also needed to set the frame of the tabBar to something outside the screen, otherwise the tabbar would not show but it will still occupy the space.

Ali
  • 18,665
  • 21
  • 103
  • 138
4

Since IOS 7.1, "Swift" solutions:

self.tabBarController?.tabBar.hidden = true // hide tabbar
self.tabBarController?.tabBar.hidden = false // show tabbar

Hope this could help!

Sifeng
  • 713
  • 9
  • 23
  • 1
    This doesn't adjust the content space of the view controllers though. Leaves a free area. – tcurdt Aug 21 '16 at 18:14
3

The solution below works fine for me in exactly the same use case where I have to move to fullscreen mode with TabBar animation.

Basically, the idea is

  1. to make a snapshot of UITabBar;

  2. add the UIImage of the snapshot to UIImageView which has the same frame as UITabBar does;

  3. resize underlying view and place it on self.tabBarController.view;

  4. set UITabBar's alpha to be 0.0;

  5. place the UIImageView with UITabBar's snapshot on the self.tabBarController.view;

  6. Once the above is achieved, do any kind of animation

    #import "QuartzCore/CALayer.h"
    
    @implementation FTBFirstViewController {
       BOOL hidden;
       UIImageView *fakeTabBarImageView;
       UIView *viewToResize;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        //////////////////////////////
        // Create your viewToResize
        //////////////////////////////
        [self.view addSubview:viewToResize];
    
        hidden = NO;
    }
    
    - (void)hideTabBar:(id)sender {
        if (!hidden) {
            //
            // to create the fake UITabBar
            fakeTabBarImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
            UIImage *fakeTabBarImage = [self imageScreenshotFromView:self.tabBarController.tabBar];
            fakeTabBarImageView.image = fakeTabBarImage;
            fakeTabBarImageView.frame = self.tabBarController.tabBar.frame;
            //
            // to resize underlying UIView
            viewToResize.frame = (CGRect){viewToResize.frame.origin.x, viewToResize.frame.origin.y + 20.f, viewToResize.frame.size.width, viewToResize.frame.size.height + fakeTabBarImageView.frame.size.height};
            //
            // to hide real UITabBar
            self.tabBarController.tabBar.alpha = 0.0;
            //
            // to add views in exactly this order
            [self.tabBarController.view addSubview:viewToResize];
            [self.tabBarController.view addSubview:fakeTabBarImageView];
            //
            // do any sort of animation
            [UIView animateWithDuration:0.8 animations:^{
                fakeTabBarImageView.frame = (CGRect){fakeTabBarImageView.frame.origin.x, fakeTabBarImageView.frame.origin.y + fakeTabBarImageView.frame.size.height, fakeTabBarImageView.frame.size};
            }];
    
            hidden = YES;
        } else {
            [UIView animateWithDuration:0.8 animations:^{
                    fakeTabBarImageView.frame = (CGRect){fakeTabBarImageView.frame.origin.x, fakeTabBarImageView.frame.origin.y - fakeTabBarImageView.frame.size.height, fakeTabBarImageView.frame.size};
            } completion:^(BOOL complete){
                self.tabBarController.tabBar.alpha = 1.0;
                [fakeTabBarImageView removeFromSuperview];
                fakeTabBarImageView = nil;
    
                viewToResize.frame = self.view.frame;
                [self.view addSubview:viewToResize];
    
                [fakeTabBarImageView removeFromSuperview];
            }]; 
    
            hidden = NO;
        }
    }
    
    - (UIImage *)imageScreenshotFromView:(UIView *)aView {
        UIImage *viewImage;
    
        UIGraphicsBeginImageContextWithOptions(aView.bounds.size, aView.opaque, [[UIScreen mainScreen] scale]);
        [aView.layer renderInContext:UIGraphicsGetCurrentContext()];
        viewImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return viewImage;
    }
    
Yevhen Dubinin
  • 4,657
  • 3
  • 34
  • 57
3

I tried pretty much all these answers but none of them worked for me. My app has a UITabBarController as the root view, and each tab has a UINavigationController. One of the UINavigationControllers has a UICollectionViewController as the top view controller. When the user selects an item in the UICollectionView, I wanted the detail view controller to get pushed onto the navigation stack. My detail view then had a toolbar at the bottom. I didn't want the toolbar to appear on top of the tab bar as that looks goofy, and switching tab contexts won't be needed from this view. I could probably have easily solved this by manually placing UIToolbars and UITabBars and not using UITabBarController and the built-in UIToolbar, but that seemed like too much refactoring and a bit inelegant.

In the end my solution was fairly simple: extend the bounds of the UITabBarController off the bottom of the screen. I added this to my detail view controller:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Extend the UITabBarController to shift the tab bar off screen
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    CGRect tabBarControllerFrame = self.tabBarController.view.frame;
    if (animated) {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.5];
        tabBarControllerFrame.size.height = screenRect.size.height +
            self.tabBarController.tabBar.frame.size.height;
        [self.tabBarController.view setFrame:tabBarControllerFrame];
        [UIView commitAnimations];
    }
    else {
        tabBarControllerFrame.size.height = screenRect.size.height +
            self.tabBarController.tabBar.frame.size.height;
        [self.tabBarController.view setFrame:tabBarControllerFrame];
    }

    // Now show the toolbar
    [self.navigationController setToolbarHidden:NO animated:animated];
}

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    // Ensure the UITabBarController remains extended when subviews are laid out
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    CGRect tabBarControllerFrame = self.tabBarController.view.frame;
    tabBarControllerFrame.size.height = screenRect.size.height + 
        self.tabBarController.tabBar.frame.size.height;
    [self.tabBarController.view setFrame:tabBarControllerFrame];
}

Then to reshow the tab bar when the user pops back to the top of my UINavigationController, I added this to my top view controller:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Hide toolbar
    [self.navigationController setToolbarHidden:YES animated:animated];

    // Tab bar back on to screen
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    CGRect tabBarControllerFrame = self.tabBarController.view.frame;
    if (tabBarControllerFrame.size.height != screenRect.size.height) {
        if (animated) {
            [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:0.5];
            tabBarControllerFrame.size.height = screenRect.size.height;
            [self.tabBarController.view setFrame:tabBarControllerFrame];
            [UIView commitAnimations];
        }
        else {
            tabBarControllerFrame.size.height = screenRect.size.height;
            [self.tabBarController.view setFrame:tabBarControllerFrame];
        }
    }
}
SeanR
  • 7,899
  • 6
  • 27
  • 38
3

you can push a modal view controller

[self presentModalViewController:myFullscreenViewController animated:YES];

this will create a completely new view fullscreen above your current one.

dismiss ist with dismissModalViewController:animated:

2

Swift and modified version of @Saurabh code

Method

func setTabBarHidden (bool:Bool){
        for view in tabBarController!.view.subviews {
            if (view.isKindOfClass(UITabBar)){
                let tabBar = view as! UITabBar
                UIView.animateWithDuration(0.3, animations: { () -> Void in
                    var offset = CGFloat(50)
                    if (bool == false){
                        offset = -50;
                    }
                    tabBar.frame = CGRect(origin: CGPointMake(tabBar.frame.origin.x, tabBar.frame.origin.y + offset), size: tabBar.frame.size)
             })   
        }
    }
}

To show

override func viewDidLoad() {
     setTabBarHidden(true)
}

To hide

override func viewWillDisappear(animated: Bool) {
    setTabBarHidden(false)
}
Husam
  • 8,149
  • 3
  • 38
  • 45
1

Updated and Working for swift 5 and ios 14.0

/*
    Shows or hides the tabbar

    :param: hidden            whether to show or hide the tabbar
    :param: animationDuration the animation's duration
*/
extension UITabBarController {
    func setHidden(hidden:Bool, animationDuration:TimeInterval = 0.25) {
        
        let screenRect = UIScreen.main.bounds
        var fHeight = screenRect.size.height
        
        if !hidden {
            fHeight -= self.tabBar.frame.size.height
        }
        
        UIView.animate(withDuration: animationDuration, animations: {
            for view in self.view.subviews {
                if view is UITabBar {
                    view.frame = CGRect(
                        x: view.frame.origin.x,
                        y: fHeight,
                        width: view.frame.size.width,
                        height: view.frame.size.height)
                }
            }
        })
    }
}

This is a more direct port (not tested):

/*
    Shows or hides the tabbar

    :param: hidden            whether to show or hide the tabbar
    :param: animationDuration the animation's duration
*/
extension UITabBarController {
    func setHidden(hidden:Bool, animationDuration:TimeInterval = 0.25) {
        
        let screenRect = UIScreen.main.bounds
        var fHeight = screenRect.size.height
        
        if UIApplication.shared.statusBarOrientation.isLandscape {
            fHeight = screenRect.size.width
        }
        
        if !hidden {
            fHeight -= self.tabBar.frame.size.height
        }
        
        UIView.animate(withDuration: animationDuration, animations: {
            for view in self.view.subviews {
                if view is UITabBar {
                    view.frame = CGRect(
                        x: view.frame.origin.x,
                        y: fHeight,
                        width: view.frame.size.width,
                        height: view.frame.size.height)
                }
                else if hidden {
                    view.frame = CGRect(
                        x: view.frame.origin.x,
                        y: view.frame.origin.y,
                        width: view.frame.size.width,
                        height: fHeight)
                }
            }
        }, completion: { finished in
            if !hidden {
                UIView.animate(withDuration: animationDuration, animations: {
                    for view in self.view.subviews {
                        if !(view is UITabBar) {
                            view.frame = CGRect(
                                x: view.frame.origin.x,
                                y: view.frame.origin.y,
                                width: view.frame.size.width,
                                height: fHeight)
                        }
                    }
                })
            }
        })
    }
}
jbafford
  • 5,528
  • 1
  • 24
  • 37
schmittsfn
  • 1,412
  • 18
  • 40
1

A swift version with animation, you need set a property isHideTabBar by yourself.

self.isHideTabBar = !self.isHideTabBar
UIView.animate(withDuration: 0.5, animations: {
    self.tabBarController?.tabBar.frame = (self.tabBarController?.tabBar.frame.offsetBy(dx: 0, dy: self.isHideTabBar ? 100 : -100))!
 })
William Hu
  • 15,423
  • 11
  • 100
  • 121
0

Hiding the tab bar is not an adequate solution, it won't adjust the current view controllers view height.

Instead you may simply transform the tab bar itself, either by it's height (to hide) or an identity transform to reset to visible.

extension UITabBarController {
    func setBarHiddenAnimated(_ hidden:Bool) {
        UIView.animate(withDuration: 0.3, animations: {
            if hidden {
                self.tabBar.transform = CGAffineTransform(translationX: 0, y: self.tabBar.frame.size.height)
            } else {
                self.tabBar.transform = CGAffineTransform.identity
            }
        })
    }
}

Note that you may need to set your view controller to 'extends below bottom bars' and 'extends under opaque bars' to remove the black background during animation.

emma ray
  • 13,336
  • 1
  • 24
  • 50