React-native: [TabBarIOS] How To Hide Tab Bar in Navigation Interface

Created on 2 Jun 2015  路  27Comments  路  Source: facebook/react-native

Most helpful comment

UPDATE: I have it working now for my situation (I wanted 3 tabs to show the tab bar and one of the tabs to hide the tab bar)

@christopherdro The proposed solution above may work in some situations, but is not ideal for what I want to do. I hope someone figures out a way to create a PR for this.

@jainmitesh09 here are the files and edits in the Objective-C code as far as i can make out from @yangaqi 's example:

In Xcode's lefthand sidebar, choose the 'Project Manger' (folder icon) to see the file structure.

The particular folder you are looking for is found at:
[YourAppName] > Libraries > React.xcodeproj > React > Views

RCTNavItem.h

#import "RCTComponent.h"

@interface RCTNavItem : UIView

//add this line:
@property (nonatomic, assign) BOOL showTabBar;

RCTNavItemManager.m

@implementation RCTNavItemManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
  return [RCTNavItem new];
}

// add this line:
RCT_EXPORT_VIEW_PROPERTY(showTabBar, BOOL)

RCTNavigator.m

- (void)navigationController:(UINavigationController *)navigationController
      willShowViewController:(__unused UIViewController *)viewController
                    animated:(__unused BOOL)animated
{

// Add these two lines:
        RCTWrapperViewController *thisController = (RCTWrapperViewController *)viewController;
        navigationController.tabBarController.tabBar.hidden = !thisController.navItem.showTabBar;

I did not need to add propTypes to NavigatorIOS.ios.js or TabBarIOS.ios.js

In order for this all to work, each tab seemingly needs to have its own NavigatorIOS component. When I had the tab simply present a screen the - (void)navigationController:(UINavigationController *)navigationController... method does not get called. This was not an issue for me, because hiding the navBar is easily done with navigationBarHidden: true.

In my case I had a TabNav > HomeNav > HomeScreen

Passing showTabBar prop in HomeNav:

  render() {
    return (
      <NavigatorIOS
        style={styles.container}
        client={this.props.client}
        initialRoute={{
          title: 'Home',
          component: HomeScreen,
          navigationBarHidden: true,
          showTabBar: false,
          passProps: { ...},
        }}/>
      );
    }
  }

I hope this helps someone!

All 27 comments

+1

+1.

I hide the tabbar with toggle the hidden property of the tabbar in tabBarController,but when i swipe back,the animation effect in tabbar disappears.Looking forward to a better hack.

You could use Navigator on your index and set the initial route to your TabBars.
Now, any new screen that is pushed will overlap your TabBar screen.

@maplebaby Were you ever able to figure out a solution?

@christopherdro: I'm guessing your proposed solution would mean that ANY scenes pushed onto the stack from that initial route would overlap and cover the tab bar?

@achang28 Yes, in that case any scene will overlap your tab bars.

+1
@christopherdro Can you give a example code? Thanks.

So the final solution is a new design form like above? Any other solution or can someone make it detail about how to achieve the above solution?

+10086

You also might want to consider using a JS-based tabbed-navigator, eg: https://github.com/exponentjs/react-native-tab-navigator

Here's the sample code.
https://rnplay.org/apps/-P8G_w

@ide @brentvatne Issue can be closed. Example and alternate method provided.

Neat, thanks @christopherdro!

Is there an alternative way that doesn't always overlap your tab bar on a new scene?

What is happening to me is that my original login screen doesn't have a tab bar. When a user logs in / signs up, all scenes have a tab bar. When the user logs out, I call this.props.navigator.push to go back to the initial route (which would be the login page) - but it has the tab bar appear on the page, which is not what I want.

I add hidesBottomBarWhenPushed in react code but tabbar is not hidden.

so I modify the RCTNavItem code,add a property control tabbar visible, like @property (nonatomic, assign) BOOL showTabBar;

in RCTNavItemManager.m RCT_EXPORT_VIEW_PROPERTY(showTabBar, BOOL)

and modify the method

  • (void)navigationController:(UINavigationController _)navigationController
    willShowViewController:(__unused UIViewController *)viewController
    animated:(__unused BOOL)animated{
    RCTWrapperViewController * thisController = (RCTWrapperViewController_)viewController;
    navigationController.tabBarController.tabBar.hidden = !thisController.navItem.showTabBar;
    ...

final add a propType in NavigatorIOS.ios.js

@yangaqi Thanks!!!

I'm not using the NavigatorIOS component; I'm using the Navigator component.

Will this solution to the issue need to be changed?

You could use nested navigators, where the top-level navigator contains two scenes: logged-out and logged-in. The logged-in scene would have a tab bar with a navigator for each tab.

@ide thanks. I'll give this a go as well.

@christopherdro in the example you provided, if the navigator has a navigation bar, it would be exactly the same navigation bar when switching between tabs. It means I need to somehow change nav bar myself when switching between tabs -- I don't even know it's possible to do so.

Any ideas on handling the nav bar? As I understood, hide/show Nav bar is also not supported...

@yangaqi Thank you! It works!

@yangaqi can you please tell me what is the filename to modify that method ?

Also, anyone has a solution working ?

UPDATE: I have it working now for my situation (I wanted 3 tabs to show the tab bar and one of the tabs to hide the tab bar)

@christopherdro The proposed solution above may work in some situations, but is not ideal for what I want to do. I hope someone figures out a way to create a PR for this.

@jainmitesh09 here are the files and edits in the Objective-C code as far as i can make out from @yangaqi 's example:

In Xcode's lefthand sidebar, choose the 'Project Manger' (folder icon) to see the file structure.

The particular folder you are looking for is found at:
[YourAppName] > Libraries > React.xcodeproj > React > Views

RCTNavItem.h

#import "RCTComponent.h"

@interface RCTNavItem : UIView

//add this line:
@property (nonatomic, assign) BOOL showTabBar;

RCTNavItemManager.m

@implementation RCTNavItemManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
  return [RCTNavItem new];
}

// add this line:
RCT_EXPORT_VIEW_PROPERTY(showTabBar, BOOL)

RCTNavigator.m

- (void)navigationController:(UINavigationController *)navigationController
      willShowViewController:(__unused UIViewController *)viewController
                    animated:(__unused BOOL)animated
{

// Add these two lines:
        RCTWrapperViewController *thisController = (RCTWrapperViewController *)viewController;
        navigationController.tabBarController.tabBar.hidden = !thisController.navItem.showTabBar;

I did not need to add propTypes to NavigatorIOS.ios.js or TabBarIOS.ios.js

In order for this all to work, each tab seemingly needs to have its own NavigatorIOS component. When I had the tab simply present a screen the - (void)navigationController:(UINavigationController *)navigationController... method does not get called. This was not an issue for me, because hiding the navBar is easily done with navigationBarHidden: true.

In my case I had a TabNav > HomeNav > HomeScreen

Passing showTabBar prop in HomeNav:

  render() {
    return (
      <NavigatorIOS
        style={styles.container}
        client={this.props.client}
        initialRoute={{
          title: 'Home',
          component: HomeScreen,
          navigationBarHidden: true,
          showTabBar: false,
          passProps: { ...},
        }}/>
      );
    }
  }

I hope this helps someone!

@mcampsall Thank you ! Got another workaround; used Navigator instead NavigatorIOS. But thanks for the solution. Appreciate it. I'll try it out with NavigatorIOS.

@jainmitesh09 How did you got this working with Navbar?
Thanks!

@horatiua, the solution i proposed above includes a nav bar (the NavigatorIOS component). Set up a TabBarIOS like normal and just return a NavigatorIOS component in each tab.

Something like this (not tested):

 render() {

    return (
      <TabBarIOS tintColor={SPColors.blue}>

        <TabBarIOS.Item
          selected={this.state.selectedTab === 'home'}
          title='Home'
          icon={require ('./Icons/IconImages/HomeTabIcon.png')}
          onPress={() => {
            this.setState({
              selectedTab: 'home'
            });
          }}>
          <NavigatorIOS
            style={styles.container}
            ref="nav"
            initialRoute={{
              title: 'Home',
              component: HomeNavigationController,
              navigationBarHidden: true,
              showTabBar: false,
              passProps: {
                //pass props here
              },
            }}/>
          </TabBarIOS.Item>


          <TabBarIOS.Item
            selected={this.state.selectedTab === 'secondTab'}
            title='Second Tab'
            icon={require ('./Icons/IconImagesSecondTabIcon.png')}
            onPress={() => this._tabPressed('secondTab')}>
          <NavigatorIOS
            style={styles.container}
            ref="nav"
            initialRoute={{
              title: 'SecondTab',
              component: SecondTabComponent,
              navigationBarHidden: false,
              showTabBar: true,
              passProps: {
                //pass props here
              },
            }}/>
          </TabBarIOS.Item>

          </TabBarIOS.Item>

          <TabBarIOS.Item
            selected={this.state.selectedTab === 'thirdTab'}
            title='Third Tab'
            icon={require ('./Icons/IconImagesThirdTabIcon.png')}
            onPress={() => this._tabPressed('thirdTab')}>
          <NavigatorIOS
            style={styles.container}
            ref="nav"
            initialRoute={{
              title: 'ThirdTab',
              component: ThirdTabComponent,
              navigationBarHidden: false,
              showTabBar: true,
              passProps: {
                //pass props here
              },
            }}/>
          </TabBarIOS.Item>

        </TabBarIOS>
      );
    }


@mcampsall
Thanks for your suggestion. The issue is that right now I've already implemented a Navigator in every TabBarIOS.Item, as it best fits my app's needs. I nested this TabBarIOS in another Navigator in order to make TabBarIOS disappear. It's an ugly solution (as I had to create some kind of router in order to work fine with Redux), but it works...
A "navigationBarHidden" property for TabBarIOS would be very useful, though.

RCTWrapperViewController.m

- (BOOL)hidesBottomBarWhenPushed
{
  return self.navigationController.viewControllers.count != 1;
}

RCTTabBar.m

- (void)reactBridgeDidFinishTransaction
{
  ...

  if (_tabsChanged) {

    NSMutableArray<UIViewController *> *viewControllers = [NSMutableArray array];
    for (RCTTabBarItem *tab in [self reactSubviews]) {
      UIViewController *controller = tab.reactViewController;
      if (!controller) {
        NSArray *tabSubViews = [[[tab reactSubviews] firstObject] reactSubviews];
        RCTNavigator *navigator = [tabSubViews firstObject];
        if (!tabSubViews.count) {
          tab.onPress(nil);
          return;
        }
        else if ([navigator isKindOfClass:[RCTNavigator class]]) {
          controller = navigator.reactViewController;
        }
        else {
          controller = [[RCTWrapperViewController alloc] initWithContentView:tab];
        }
      }
      [viewControllers addObject:controller];
    }

    _tabController.viewControllers = viewControllers;
    _tabsChanged = NO;
    RCTTabBarItem *tab = (RCTTabBarItem *)[[self reactSubviews] firstObject];
    tab.onPress(nil);
  }

  ...

}
Was this page helpful?
0 / 5 - 0 ratings