My goal is to have both Top and Bottom navigation bar for Home, Dashboard, and Album, but not for the SignIn. Here's the catch, I wish to put the button on the bottom instead of on the top.
The last remaining puzzle is how to add a Sign In button to the Bottom Navigation Bar.
The roadblock is if you write <Tab.Screen name="Sign In component={SignIn} /> and you press a button with parameter onPress={() => navigation.navigate('SignIn')}, it will navigate you to the Tab.Screen instead of Stack.Screen.
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Dashboard" component={Dashboard} />
<Tab.Screen name="Album" component={Album} />
</Tab.Navigator>
);
}
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen options={{title: ''}} name="MyTabs" component={MyTabs} />
<Stack.Screen name="SignIn" component={SignIn} />
</Stack.Navigator>
);
}
export default function App() {
return (
<Provider store={store}>
<NavigationContainer>
<MyStack />
</NavigationContainer>
</Provider>
);
}
You can use the tabbarbutton like below. This would pass the props and render a the touchableopacity and you can have your own onPress.
You can navigate, here i have given an alert
<Tab.Screen name="Settings"
options={({navigation})=> ({
tabBarButton:props => <TouchableOpacity {...props} onPress={()=>navigation.navigate('SignIn')}/>
})}/>
Related
I have developed a bottomTabNavigator in react-native and I have 3 main routes which I want to show in my bottomtabnavigator which are 1) Home, 2) Profile, 3) Chat, So I wrote the following code:
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
const Navigation = () => {
return (
<>
<Tab.Navigator>
{user.authLoadingState ? (
<Tab.Screen name="Home" component={LoadingScreen} />
) : user.isLoggedIn ? (
<>
<Tab.Screen
name="Home"
component={HomeScreen}
/>
<Tab.Screen
name="Profile"
component={ProfileScreen}
/>
<Tab.Screen
name="Chat"
component={ChatScreen}
/>
<Stack.Screen name="Update" component={UpdateScreen} /> // this is the screen I don't want in my bottomTab but I want to navigate to it using useNavigation hook.
</>
) : (
<>
<Stack.Screen name="First" component={FirstScreen} />
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={RegisterScreen} />
</>
)}
</Tab.Navigator>
</>
);
};
Now, when I go to my Profile screen, I have a button which (should) navigate to another screen which is not mentioned in my Tab Navigator definition, how can I navigate to that screen because obviously I do not want to fill my bottomTabNavigator with different screens, I only want to keep the main screens in my bottomTabNavigator not all. When I was using Stack.Navigator alone, it was fine because I could just keep all my screens under <Stack.Navigator></Stack.Navigator> and navigate to any screen using navigator.navigate(nameOfScreen) with const navigator = useNavigation(). But now, if a screen which is not mentioned inside Tab.Navigator will throw an error if I navigate saying Screen does not exists. Is there any thing I could do to make it work?
to navigate between tab and stack screen you can do this way :
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeScreen}
/>
<Tab.Screen name="Profile Screen" component={StackScreens} />
<Tab.Screen
name="Chat"
component={ChatScreen}
/>
</Tab.Navigator>
</NavigationContainer>
)
function StackScreens() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }} >
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Update" component={UpdateScreen} /> // this is the screen I don't want in my bottomTab but I want to navigate to it using useNavigation hook.
</Stack.Navigator>
);
}
}
I'm not sure if it is exactly that you want, but you can now access from "Profile" to the "UpdateScreen" without showing it in the bottomTabNavigator
This is my tab navigator:
<Tab.Navigator initialRouteName="Home" backBehavior="initialRoute">
<Tab.Screen
name="Science"
component={Science}
options={{
tabBarLabel: 'Science',
tabBarIcon: ({color, size}) => (
<Image source={require('../../assets/images/science-tab.png')} />
),
}}
/>
<Tab.Screen name="Dashboard" component={Dashboard} />
</Tab.Navigator>
This is DrawerNavigator:
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
And this is my root navigator: Below Bottomnavigation is the tab navigator.
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="BottomNavigation"
component={BottomNavigation}
options={{title: this.createTitle()}}
/>
</Stack.Navigator>
</NavigationContainer>
I recommend you to make your TabNavigator a screen of DrawerNavigator
You can do something like this:
function TabNavigator({navigation}) {
return (
<Tab.Navigator>
// Your tab screens
</Tab.Navigator>
);
}
function DrawerNavigator() {
return (
<Drawer.Navigator>
<Drawer.Screen name="TabNavigator" component={TabNavigator} />
</Drawer.Navigator>
);
}
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="DrawerNavigator" component={DrawerNavigator} />
</Stack.Navigator>
</NavigationContainer>
);
};
If you want to open your drawer, you can call navigation.openDrawer() in your TabNavigator.
Update to address label issue
You can create a drawer content component to override the default behavior of adding the DrawerNavigator screens' labels as the content of the drawer.
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
label="Home"
onPress={() => props.navigation.navigate('Home')}
/>
// ...
</DrawerContentScrollView>
);
}
Then you need to change the DrawerNavigator to this:
function DrawerNavigator({route}) {
return (
<Drawer.Navigator
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="TabNavigator" component={TabNavigator} />
<Drawer.Screen name="Home" component={Home} />
</Drawer.Navigator>
);
}
So you can add new screens to your DrawerNavigator and navigate to them using the DrawerItem onPress function.
Of course make sure to import DrawerContentScrollView, DrawerItemList and DrawerItem from #react-navigation/drawer.
For more info look at: https://reactnavigation.org/docs/drawer-navigator/#providing-a-custom-drawercontent.
Follow the instruction of ReactNative, when "we start on the HomeScreen and navigate to DetailsScreen. Then we use the tab bar to switch to the SettingsScreen and navigate to ProfileScreen. After this sequence of operations is done, all 4 of the screens are mounted! If you use the tab bar to switch back to the HomeStack, you'll notice you'll be presented with the DetailsScreen - the navigation state of the HomeStack has been preserved!"
But I want when I switch back to the HomeStack, it will be presented with the HomeScreen, not the DetailsScreen. Someone can help me, thankss <3
function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="First">
{() => (
<SettingsStack.Navigator>
<SettingsStack.Screen
name="Settings"
component={SettingsScreen}
/>
<SettingsStack.Screen name="Profile" component={ProfileScreen} />
</SettingsStack.Navigator>
)}
</Tab.Screen>
<Tab.Screen name="Second">
{() => (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
)}
</Tab.Screen>
</Tab.Navigator>
</NavigationContainer>
);
}
You can use onTabPress method, like below:
OnTabPress({navigation})=>{
navigation.navigate("HomeStack",{
screen: "Home"
}).
}
This is my tab navigator:
<Tab.Navigator initialRouteName="Home" backBehavior="initialRoute">
<Tab.Screen
name="Science"
component={Science}
options={{
tabBarLabel: 'Science',
tabBarIcon: ({color, size}) => (
<Image source={require('../../assets/images/science-tab.png')} />
),
}}
/>
<Tab.Screen name="Dashboard" component={Dashboard} />
</Tab.Navigator>
This is DrawerNavigator:
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
And this is my root navigator: Below Bottomnavigation is the tab navigator.
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="BottomNavigation"
component={BottomNavigation}
options={{title: this.createTitle()}}
/>
</Stack.Navigator>
</NavigationContainer>
I recommend you to make your TabNavigator a screen of DrawerNavigator
You can do something like this:
function TabNavigator({navigation}) {
return (
<Tab.Navigator>
// Your tab screens
</Tab.Navigator>
);
}
function DrawerNavigator() {
return (
<Drawer.Navigator>
<Drawer.Screen name="TabNavigator" component={TabNavigator} />
</Drawer.Navigator>
);
}
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="DrawerNavigator" component={DrawerNavigator} />
</Stack.Navigator>
</NavigationContainer>
);
};
If you want to open your drawer, you can call navigation.openDrawer() in your TabNavigator.
Update to address label issue
You can create a drawer content component to override the default behavior of adding the DrawerNavigator screens' labels as the content of the drawer.
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
label="Home"
onPress={() => props.navigation.navigate('Home')}
/>
// ...
</DrawerContentScrollView>
);
}
Then you need to change the DrawerNavigator to this:
function DrawerNavigator({route}) {
return (
<Drawer.Navigator
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="TabNavigator" component={TabNavigator} />
<Drawer.Screen name="Home" component={Home} />
</Drawer.Navigator>
);
}
So you can add new screens to your DrawerNavigator and navigate to them using the DrawerItem onPress function.
Of course make sure to import DrawerContentScrollView, DrawerItemList and DrawerItem from #react-navigation/drawer.
For more info look at: https://reactnavigation.org/docs/drawer-navigator/#providing-a-custom-drawercontent.
Stack navigation is parent and tab navigation is child
I want to hide the button when I press the "settings" tab.
using `react-navigation ver.5
please help me.
child
const Tab = createBottomTabNavigator();
const Tabs = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Observatory" component={Observatory} />
<Tab.Screen name="Search" component={Search} />
<Tab.Screen name="Setting" component={Setting} />
</Tab.Navigator>
);
}
parent
const Stack = createStackNavigator();
export default App = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Tabs"
component={Tabs}
options={({ navigation, route }) => ({
headerRight: () => (
<Icon
name="edit"
size={30}
color="#000"
onPress={() => navigation.navigate('Template')}
/>
),
})}
/>
<Stack.Screen name="Template" component={Template} />
</Stack.Navigator>
</NavigationContainer>
);
}