Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to set header for TabNavigator? #741

Closed
AdamChrist opened this issue Mar 20, 2017 · 14 comments
Closed

how to set header for TabNavigator? #741

AdamChrist opened this issue Mar 20, 2017 · 14 comments

Comments

@AdamChrist
Copy link

@AdamChrist AdamChrist commented Mar 20, 2017

header props is not work in TabNavigator's navigationOptions.So I have no way to define right for header .
How can each tab have a right button in header ?

@kamalk333

This comment has been minimized.

Copy link

@kamalk333 kamalk333 commented Mar 20, 2017

TabNavigator() function provides the ability that you want.
tab navigator function accepts two parameters, routeConfig and tabNavigatorConfig.
In tabNavigatorConfig, you can play with whatever you need. I'll share a link for you to look at.

https://reactnavigation.org/docs/navigators/tab#TabNavigatorConfig

@InteractiveLogic

This comment has been minimized.

Copy link

@InteractiveLogic InteractiveLogic commented Mar 31, 2017

Is it my imagination or do we have to embed a StackNavigator to actually generate a header in the first place? I couldn't even get a header to appear without getting a StackNavigator in the mix... it feels like I was doing something incorrectly but if it works, that's good enough for me right now.

However, I'd still like to know if that's the correct way of doing it...

@rewieer

This comment has been minimized.

Copy link

@rewieer rewieer commented Mar 31, 2017

I guess that according to @kamalk333 you have to provide your own custom tabbar with your header to have it

@jkbreunig

This comment has been minimized.

Copy link

@jkbreunig jkbreunig commented Apr 5, 2017

How to set top tabbar beneath header?
Update:
Initially I had a top StackNavigator and a TabNavigator and Login screen routes, and each tab had a StackNavigator. With this setup I wasn't able to hide the header or tabbar when pushing a screen with a tab's StackNavigator. To get this to work I added each tab screen as a route directly on the TabNavigator and added any screen that shouldn't have the tabbar visible as a route on the top StackNavigator.

@grabbou

This comment has been minimized.

Copy link
Collaborator

@grabbou grabbou commented Apr 24, 2017

The answer is:

StackNavigator({
   MyTab: {
     screen: TabNavigator({ }),
     navigationOptions: { title: 'Header title' }
  }
})

You have to put it inside Stack to get a header component.

@grabbou grabbou closed this Apr 24, 2017
@0x6e6562

This comment has been minimized.

Copy link

@0x6e6562 0x6e6562 commented Jun 8, 2017

@grabbou Thanks for the tip about nesting the TabNavigator inside the StackNavigator to get headers - this is working well for me.

Following on from this, I was wondering what the idiomatic way is to handle a complete navigation reset, since I haven't found a function to reset the router and I've had to use what feels like a bit of a hack.

Given this nested config:

const Routes = {
    First: { screen: FirstScreen },
    Second: { screen: SecondScreen },
    Settings: { screen: SettingsScreen },
};

const TabConfig = {
  stateName: 'MainNavigation',
  tabBarOptions: {
    activeTintColor: '#e91e63',
    labelStyle: {
      fontSize: 12,
    },
  },
};

If I dispatch a reset to the to the TabNavigator using #1384

const resetMain = NavigationActions.reset({
   index: 0,
   stateName: 'MainNavigation',
   actions: [
     NavigationActions.navigate({ routeName: 'First' })
   ]
});

This will not reset the TabNavigator to it's initial state. I'm not quite sure whether this is part of the scope of #1384, but more generally what it means to reset a TabNavigator.

So to work around this, I've tried to make the parent StackNavigator rebuildable:

const buildStack = () => (
  StackNavigator({
    screen: {
      screen: TabNavigator(Routes, TabConfig),
    }
  })
)

Using this builder, I can create the initial stack and then I can subscribe to the Navigation/RESET action and in this case I re-initialize the stack:

const Stack = buildStack();

export const navigationReducer = (state, action) => {
  if (action.type === 'Navigation/RESET') {
    const resetStack = buildStack();
    return resetStack.router.getStateForAction(action, null);
  }
  return Stack.router.getStateForAction(action,state);
}

This feels like I'm missing the point somewhere - is there a more idiomatic way to achieve this?

@BransonGitomeh

This comment has been minimized.

Copy link

@BransonGitomeh BransonGitomeh commented Jul 20, 2017

I have the tab navigator under inside stack navigator, and i want to have the tab navigator to have the same elevation as the header to have the same look... Any clues? any support for this that's simple?

@andynguy3n

This comment has been minimized.

Copy link

@andynguy3n andynguy3n commented May 25, 2018

Thanks @grabbou,
It worked for me. I'm wondering. How can I change the title for each screen inside TabNavigator?
Many thanks.

@hezhii

This comment has been minimized.

Copy link

@hezhii hezhii commented Jun 1, 2018

@itanhduy Have you solved it?

@cordosvictor

This comment has been minimized.

Copy link

@cordosvictor cordosvictor commented Nov 23, 2018

Thanks @grabbou. Wrapping the TabNavigator with a StackNavigator works nicely.
@itanhduy @hezhii Found a way to change the title for each screen (using React Navigation v2 API).

const getCurrentRoute = (navigationState) => {
    if (!navigationState) {
        return null
    } else if (!navigationState.routes) {
        return navigationState
    }

    const route = navigationState.routes[navigationState.index]
    if (route.routes) {
        return getCurrentRoute(route)
    }

    return route
}

const Routes = {
   TabStack: { key: "TabStack" },

   Screen1: { key: "Screen1", title: "Screen 1" }, 
   Screen2: { key: "Screen2", title: "Screen 2" },
   Screen3: { key: "Screen3", title: "Screen 3" },
}

const tabNavigator = createMaterialTopTabNavigator({
      [Routes.Screen1.key]: { screen: FirstScreen },
      [Routes.Screen2.key]: { screen: SecondScreen },
      [Routes.Screen3.key]: { screen: ThirdScreen },
   }, {
      initialRouteName: Routes.Screen1.key,
      ...
      tabBarOptions: { ... }
   }
)

const mainNavigator = createStackNavigator({
      [Routes.TabStack.key]: tabNavigator
   }, {
      initialRouteName: Routes.TabStack.key,
      navigationOptions: ({ navigation }) => {
         // triggered each time you're changing a tab

         const navRoute = getCurrentRoute(navigation.state)
            , route = navRoute && navRoute.routeName && Routes[navRoute.routeName]
            , title = route ? route.title : ""

         return { title }
      }
   })
)

export default mainNavigator

And each time you're changing a tab, mainNavigator's navigationOptions will trigger.

@chj-damon

This comment has been minimized.

Copy link

@chj-damon chj-damon commented Apr 22, 2019

what if It's not just a title, but a custom component???
If I wrap a stack navigator in Tab navigator, I need to hide tabbar if I navigate to some inner screens under the stack. and also, the default navigate.goBack() can not work as expected. Isn't there a better way to solve this?

@StefanDimov

This comment has been minimized.

Copy link

@StefanDimov StefanDimov commented Sep 7, 2019

Hey guys,

This is how I solved the problem for my project:

const aScreen = () => {
  // Screen Implementation
}

const makeAScreenConfig = navigation => {
  // return navigationOptions to set on TabsNavigator
  return {
    title: 'Habits',
    headerRight: (<MaterialIcons name="add" size={30} />),
  }
}

import { aScreen, makeAScreenConfig } from './aScreen'
import { bScreen, makeBScreenConfig } from './bScreen'
import cScreen from './cScreen'

const Tabs = createBottomTabNavigator(
  { aScreen, bScreen },
  {
    navigationOptions: ({ navigation }) => {
      const { routeName } = navigation.state.routes[navigation.state.index]

      if (routeName === 'aScreen') {
        return makeAScreenConfig(navigation)
      }

      if (routeName === 'bScreen') {
        return makeBScreenConfig(navigation)
      }
    },
  },
)

const MainStack = createStackNavigator({ Tabs, cScreen })
const AppContainer = createAppContainer(MainStack)

Basically I pass the Tab Screen configuration to be set on the TabNavigator so it can be read from the StackNavigator on top.

It's a little dirty, but in case of a TabNavigator you won't have that many tabs so it's not that bad of a solution.

@avitorio

This comment has been minimized.

Copy link

@avitorio avitorio commented Sep 27, 2019

@chj-damon I have used @grabbou's answer and worked it out like this:

navigationOptions: navigation => (
    {
        header: <Header {...navigation} />,
    }),
    cardStyle: {
        backgroundColor: 'black',
    },
@Stringsaeed

This comment has been minimized.

Copy link

@Stringsaeed Stringsaeed commented Nov 18, 2019

the best way to control every screen it would be like this:

- tabs
    - screenKey:
        - stack
            - screen1
            - navigation options
                - header
    - screenKey:
        - stack
            - screen2
            - navigation options
                - header 
// example.js
const tabs = createBottomTabNavigator(
	{
		home: {
			// home screen with search bar in header,
			screen: createStackNavigator(
				{ConnectedHomeScreen},
				{
					defaultNavigationOptions: {
						header: (
							<Appbar.Header>
								<View style={{flex: 1}}>
									<Searchbar value="" />
								</View>
							</Appbar.Header>
						),
					},
				},
			),
		},
		settings: {
			// categories screen with search bar,
			screen: createStackNavigator(
				{ConnectedSettingsScreen},
				{
					defaultNavigationOptions: {
						header: (
							<Appbar.Header>
								<View style={{flex: 1}}>
									<Searchbar value="" />
								</View>
							</Appbar.Header>
						),
					},
				},
			),
		},
	},
	{
		initialRouteName: 'home',
	},
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.