facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.84k stars 24.29k forks source link

[TabBarIOS] How To Hide Tab Bar in Navigation Interface #1489

Closed maplebaby closed 9 years ago

maplebaby commented 9 years ago

How To Hide Tab Bar in Navigation Interface

scyankai commented 9 years ago

+1

skyline75489 commented 9 years ago

+1.

wingofshadow commented 9 years ago

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.

christopherdro commented 9 years ago

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.

albertwchang commented 9 years ago

@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?

christopherdro commented 9 years ago

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

feilaoda commented 9 years ago

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

0517 commented 9 years ago

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?

yangaqi commented 9 years ago

+10086

brentvatne commented 9 years ago

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

christopherdro commented 9 years ago

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

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

brentvatne commented 9 years ago

Neat, thanks @christopherdro!

apaquino commented 9 years ago

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.

yangaqi commented 9 years ago

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

final add a propType in NavigatorIOS.ios.js

apaquino commented 9 years ago

@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?

ide commented 9 years ago

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.

apaquino commented 9 years ago

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

kkgelu commented 8 years ago

@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...

Rusya13 commented 8 years ago

@yangaqi Thank you! It works!

rathodmitesh916 commented 8 years ago

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

rathodmitesh916 commented 8 years ago

Also, anyone has a solution working ?

mcampsall commented 8 years ago

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!

rathodmitesh916 commented 8 years ago

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

horatiua commented 8 years ago

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

mcampsall commented 8 years ago

@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>
      );
    }
horatiua commented 8 years ago

@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.

longminxiang commented 7 years ago

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);
  }

  ...

}