I'm using react-navigation for navigating between screens. Is it possible to have createBottomTabNavigator with 3 tabs, but when you show tab bar, I want to have visible only 2 tabs instead of 3. ?
I'm using react-navigation for navigating between screens. Is it possible to have createBottomTabNavigator with 3 tabs, but when you show tab bar, I want to have visible only 2 tabs instead of 3. ?
I made a npm package for this, please see;
https://www.npmjs.com/package/react-navigation-selective-tab-bar
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow
*/
import React, { Component } from "react";
import { Platform, StyleSheet, Text, View, Button } from "react-native";
import { createBottomTabNavigator, createAppContainer } from "react-navigation";
import BottomTabBar from "react-navigation-selective-tab-bar";
class ScreenOne extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen One</Text>
<Text style={styles.number}>1</Text>
<Text style={styles.instructions}>
I AM on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenTwo extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Two</Text>
<Text style={styles.number}>2</Text>
<Text style={styles.instructions}>
I am NOT on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenThree extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Three</Text>
<Text style={styles.number}>3</Text>
<Text style={styles.instructions}>
I AM on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenFour extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Four</Text>
<Text style={styles.number}>4</Text>
<Text style={styles.instructions}>
I am NOT on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF"
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10
},
instructions: {
textAlign: "center",
color: "#333333",
marginBottom: 5
},
number: {
fontSize: 50
},
buttons: {
flexDirection: "row"
}
});
const AppNavigator = createBottomTabNavigator(
{
One: {
screen: ScreenOne
},
Two: {
screen: ScreenTwo
},
Three: {
screen: ScreenThree
},
Four: {
screen: ScreenFour
}
},
{
tabBarComponent: props => {
return (
<BottomTabBar
{...props} // Required
display={["One", "Three"]} // Required
background="black" // Optional
/>
);
}
}
);
export default createAppContainer(AppNavigator);
Put your third item/screen in a stack navigator:
const Bottom = createBottomTabNavigator({
item1: {screen: Screen1},
item2: {screen: Screen2},
},{
initialRouteName: "item1",
}
)
export default createStackNavigator({
tabs: Bottom,
item3: Screen3,
})
At last, to change the screen to your third route in your component, you can do this:
// ...
import {withNavigation} from 'react-navigation' // IMPORTANT
export default class Example extends React.Component{
render(){
return(
<TouchableOpacity onPress={() => this.props.navigation.navigate('item3')}>
)
}
}
export default withNavigation(Example) // IMPORTANT
https://github.com/react-navigation/react-navigation/issues/5230#issuecomment-649206507
Here is how you can tell the tab navigator to not render certain routes.
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarButton: [
"Route1ToExclude",
"Route2ToExclude"
].includes(route.name)
? () => {
return null;
}
: undefined,
})}
>
This worked for me, you are still able to navigate to the tab! I changed it to this:
Without a variable:
tabBarButton: ["About"].includes(route.name) ? () => null : undefined
With a variable to hide specific tabs:
const hiddenTabs = ["About", "Food"];
tabBarButton: hiddenTabs.includes(route.name) ? () => null : undefined
With a variable to show specific tabs only:
const tabsToShow = ["About", "Food"];
tabBarButton: !tabsToShow.includes(route.name) ? () => null : undefined
All credit goes to Ben Awad!
For example, if you want to have 5 active routes in a createBottomTabNavigator, but only 3 or another number to show icons in the TabBar. In this case, all 5 routes will be active, and you can go to them props.navigation.navigate()
You must pass a filtered list of routes to the TabBar component, but the object must be sure to be deeply copied (using lodash for example)
import cloneDeep from 'lodash/cloneDeep';
....
const TabBarComponent = props => {
const routeNamesToHide = [
'MyOfficeStack',
'ArenaStack',
'SavedSearchesStack',
'NotificationsStack',
];
// Delete from TABBAR items in array 'routeNamesToHide'
let newNavigation = cloneDeep(props.navigation);
newNavigation.state.routes = newNavigation.state.routes.filter(
item => !routeNamesToHide.includes(item.routeName)
);
//
return <BottomTabBar {...props} navigation={{ ...newNavigation }} />;
};
const tabNavigator = createBottomTabNavigator(
{
SearchStack,
FavouritesStack,
AddScreenStack,
MessagesStack,
BookingsStack,
MyOfficeStack,
AreaStack,
SavedSearchesStack,
NotificationsStack,
},
{
lazy: false,
tabBarOptions: {
showLabel: true,
},
tabBarComponent: props => (
<TabBarComponent {...props} />
),
}
);
the easiest solution is this
<Tab.Screen
name='someroute'
component={SomeComponent}
options={{
tabBarButton: props => null,
}}
/>
this is by far the best solution because it doesn't require extra effort
Ben Awad solution(mentioned by Kayden van Rijn) is good, it allows centralized control, but you need extra effort to make sure the type of the route name array is correct
<Tab.Navigator
screenOptions={({ route }) => {
const toExclude: typeof route.name[] = ['routeName']
return {
tabBarButton: toExclude.includes(route.name)
? () => {
return null
}
: undefined,
}
}}
>