Drawer navigation hearder icon opening a different drawer - react-native

I have this nested structure, where I have a drawer navigation in the home page and one of pages navigates to another drawer navigation, in order to have the back button I added headerRight and HeaderLeft. The headerRight is supposed to open the child navigator but instead it goes back to open the parent navigator. Any help
const SFrench = () => {
const navigation= useNavigation()
return (
<Drawer.Navigator
screenOptions={{
drawerStyle: {
backgroundColor: Colors.primary,
},
drawerActiveTintColor: Colors.secondary,
drawerInactiveTintColor: 'white',
headerLeft: () => {
return (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<CustomItem
iconName= {Platform==='android'? 'arrow-back' : "arrow-back-ios" }
onPress={() =>
navigation.pop()
}
/>
</HeaderButtons>
);
},
headerRight: () => {
return (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<CustomItem
iconName= "menu"
onPress={() =>
navigation.toggleDrawer()
}
/>
</HeaderButtons>
);
},
}}>
<Drawer.Screen key="1" name="page 1" component={SFPage1} />
<Drawer.Screen key="2" name="page 2" component={SFPage2} />
<Drawer.Screen key="3" name="page 3" component={SFPage3} />
</Drawer.Navigator>
);
};

Related

React native bottom tab navigate to desire screen

First I create Bottomtabs and import in Core navigator;
const BottomTabs = createBottomTabNavigator();
function BottomTabNavigator({ navigation, route }) {
return (
<BottomTabs.Navigator>
<BottomTabs.Screen
name="ExploreTab"
component={ExploreNavigator}
/>
<BottomTabs.Screen
name="FormScreen"
component={ProfileNavigator}
options={({ navigation }) => ({
tabBarLabel: "",
tabBarButton: (props) => (
<TouchableOpacity
{...props}
onPress={() => {
console.log({ navigation });
navigation.navigate("FormScreen");
}}
>
<View>
<Icon
type="font-awesome-5"
name="plus"
size={moderateScale(25)}
color={Colors.white}
/>
</View>
</TouchableOpacity>
),
})}
/>
<BottomTabs.Screen
name="ProfileTab"
component={ProfileNavigator}
/>
</BottomTabs.Navigator>
);
}
export default BottomTabNavigator;
The bottom tab navigator is part of the core navigator and the core navigator is the app-level navigator.
function CoreNavigator() {
return (
<CoreStack.Navigator>
<CoreStack.Screen
name="BottomTabNavigator"
component={BottomTabNavigator}
options={{
headerShown: false,
}}
/>
<CoreStack.Screen name="AboutScreen" component={AboutScreen} />
<CoreStack.Screen name="WebScreen" component={WebScreen} />
</CoreStack.Navigator>
);
}
when I click on the bottom tab middle plus button. It should navigate to the form screen FormScreen.
Check image
In simple words below code not working which is present at the Botton tab navigator.
when I click on the bottom plus button Bellow app navigates to ProfileNavigators default screen. I want the app to navigate to FormScreen.
<BottomTabs.Screen
name="FormScreen"
component={ProfileNavigator}
options={({ navigation }) => ({
tabBarLabel: "",
tabBarButton: (props) => (
<TouchableOpacity
{...props}
onPress={() => {
console.log({ navigation });
navigation.navigate("FormScreen");
}}
>
<View>
<Icon
type="font-awesome-5"
name="plus"
size={moderateScale(25)}
color={Colors.white}
/>
</View>
</TouchableOpacity>
),
})}
/>
Try to use:
navigation.reset({
index: 0,
routes: [{ name: 'FormScreen' }],
});
Instead of navigation.navigate("FormScreen");

react-navigation [v6] drawer and stack nesting issues

Like the most common use case, I want to have a drawer in my react-native application where, from all screens header I can open/close the drawer, navigate to them. Also, each screen has an option (button, card,...) that on press should navigate to any other screen.
So I have defined the following structure. But there are several problems;
Drawer cannot recognize which screen in on focus now.
Drawer type check does not give auto-suggestions on navigation prop (e.g. props.navigation.navigate(" /* no suggestion on the present screens in the stack*/"))
On Android I feel that the overall performance drops significantly
So is this a good structure? From the official documentation, I could not find any hint on how to implement it? stack nested in drawer or vise-versa?
export type MainStackParamList = {
HomeScreen: undefined;
OverViewScreen: undefined;
WorkOrdersScreen: {id?: number; description?: string; tabIndex?: number};
PropertiesScreen: undefined;
PropertyDetailScreen: {propertyUnit: PropertyUnit};
};
export type MainDrawerParamList = {MainStack: NavigatorScreenParams<MainStackParamList>};
export type AppNavigationCompositeProps = CompositeScreenProps<
DrawerScreenProps<MainDrawerParamList, 'MainStack'>,
StackScreenProps<MainStackParamList>
>;
//____The navigation part______
const MainStack = createStackNavigator<MainStackParamList>();
const Drawer = createDrawerNavigator<MainDrawerParamList>();
/* the composite type is the only way I found to have access to
drawer fucntions such as toggleDrawer in the stack screens*/
const MainStackScreens = (navigation: AppNavigationCompositeProps) => (
<MainStack.Navigator initialRouteName={'HomeScreen'} screenOptions={MainStackScreenOptions(navigation)}>
<MainStack.Screen name="HomeScreen" component={HomeScreen} />
<MainStack.Screen name="OverViewScreen" component={OverViewScreen} />
<MainStack.Screen name="WorkOrdersScreen" component={WorkOrdersScreen} />
<MainStack.Screen name="PropertiesScreen" component={PropertiesScreen} />
<MainStack.Screen name="PropertyDetailScreen" component={PropertyDetailScreen} />
</MainStack.Navigator>
);
const Navigation: React.FC<{}> = () => {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="MainStack"
screenOptions={{headerShown: false}}
drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="MainStack" component={MainStackScreens} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default Navigation;
const MainStackScreenOptions = (navigation: AppNavigationCompositeProps): StackNavigationOptions => {
return {
headerStyle: {backgroundColor: '#00aade'},
headerTintColor: '#fca903',
headerTitleAlign: 'center',
headerTitleStyle: {fontWeight: 'bold', fontStyle: 'italic'},
headerBackTitle: 'GoBack',
headerLeft: () => <IconButton icon="menu" color="white" onPress={() => navigation.navigation.openDrawer()} />
};
};
//___the drawer content is like
const CustomDrawerContent: React.FC<DrawerContentComponentProps> = props => {
return (
<DrawerContentScrollView>
<Drawer.Item label="Home" onPress={() => props.navigation.navigate('HomeScreen')} icon="star" />
<Drawer.Item label="OverView" onPress={() => props.navigation.navigate('OverViewScreen')} icon="star" />
<Drawer.Item label="WorkOrders" onPress={() => props.navigation.navigate('WorkOrdersScreen')} icon="star" />
<Drawer.Item label="Properties" onPress={() => props.navigation.navigate('PropertiesScreen')} icon="star" />
</DrawerContentScrollView>
);
};

Opening the Drawer navigator from the bottom tab

I'm upgrading my App from react-navigation 4 to 5.
In version 4 I have a tab that open the drawer using the following code
const MainNavigator = createBottomTabNavigator(
{
More: {
screen: AdminNavigator,
navigationOptions: {
tabBarIcon: (tabInfo) => {
//return <Ionicons name="ios-star" size={25} color={tabInfo.tintColor} />;
return (
<Icon
name="tune"
color={tabInfo.tintColor}
size={tabInfo.focused ? 32 : 28}
style={{
paddingTop: 10,
}}
/>
);
},
tabBarColor: Colors.primary,
tabBarOnPress: ({ navigation }) => {
navigation.openDrawer();
},
},
},
}
In new version 5 I have the following Navigation config
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={TabsScreen} />
<Drawer.Screen name="Favorites" component={FavoritesStackScreen} />
<Drawer.Screen name="Language" component={LanguageStackScreen} />
</Drawer.Navigator>
</NavigationContainer>
where TabScreen is my bottom tab navigator
const TabsScreen = () => (
<Tabs.Navigator>
<Tabs.Screen name={"Home"} component={HomeStackScreen} />
<Tabs.Screen name={"Cocktails"} component={CocktailsStackScreen} />
<Tabs.Screen
name={"More"}
component={HomeStackScreen}
options={{
...
}}
/>
</Tabs.Navigator>
);
I'm looking for the equivalent in V5 of the following
tabBarOnPress: ({ navigation }) => {
navigation.openDrawer();
},
Try the following:
<Tabs.Screen
name={"More"}
component={HomeStackScreen}
listeners={({ navigation }) => ({
tabPress: e => {
e.preventDefault();
navigation.openDrawer();
}
})}
/>
https://reactnavigation.org/docs/navigation-events/#listeners-prop-on-screen

How to call toggleDrawer in React Navigation 5

I got a React-Navigation 5 drawer menu working using gesture, but I also want to add an icon on the right side of the header to toggle the drawer menu.
I have the navigation setup in my App.js like this:
import {NavigationContainer, DrawerActions} from '#react-navigation/native';
//....... other imports
const HomeStack = createStackNavigator();
const HomeStackScreens = () => (
<HomeStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#5C6BC0',
},
headerTintColor: '#fff',
headerRight: () => {
return (
<TouchableOpacity
onPress={() => DrawerActions.toggleDrawer()}>
<Icon name="bars" color="#FFF" size={18} />
</TouchableOpacity>
);
},
}}>
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
header:({scene, previous, navigation}) => {
return (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<Icon name="bars" color="#FFF" size={18} />
</TouchableOpacity>
);
}
}}
/>
<HomeStack.Screen name="Login" component={Login} />
<HomeStack.Screen name="Register" component={Register} />
</HomeStack.Navigator>
);
const ProfileStack = createStackNavigator();
const ProfileStackScreens = () => (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={Profile} />
</ProfileStack.Navigator>
);
const SettingStack = createStackNavigator();
const SettingStackScreens = () => (
<SettingStack.Navigator>
<SettingStack.Screen name="Profile" component={Profile} />
</SettingStack.Navigator>
);
const Drawer = createDrawerNavigator();
const DrawerScreens = () => (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeStackScreens} />
<Drawer.Screen name="Profile" component={ProfileStackScreens} />
<Drawer.Screen name="Settings" component={SetttingStackScreens} />
</Drawer.Navigator>
);
class MyApp extends React.Component {
render() {
return (
<NavigationContainer>
<DrawerScreens />
</NavigationContainer>
);
}
}
export default MyApp;
All my others screen are in the form "export default class ScreenName extends React.Component". They are imported in App.js to setup the navigation. The initial screen is Home. The icon is showing correctly on the right side of the header. Calling "DrawerActions.toggleDrawer()" directly does nothing.
I tried "this.props.navigation.toggleDrawer()", and it throws error because "this.props" is undefined.
How can I invoke toggleDrawer() with such a navigation setup? Any help is really appreciated!
Here is the final solution I come up with that requires minimal changes to my original code. The key is to receive "navigation" in screenOptions or options, then I can call navigation methods in the children of screenOptions/options.
<HomeStack.Navigator
screenOptions={({navigation}) => ({
headerStyle: {
backgroundColor: '#5C6BC0',
},
headerTintColor: '#fff',
headerRight: () => {
return (
<TouchableOpacity
style={{paddingRight: 8}}
onPress={() => navigation.toggleDrawer()}>
<Icon name="bars" color="#FFF" size={18} />
</TouchableOpacity>
);
},
})}>

react-navigation: Navigate to a different screen from a button in header

I have a Icon on the right side of my header and on press of that button i want to navigate to a different screen.
I have searched very much for this but all of the solutions are for class components and there are no official documentation available for it.
I am using react native version 0.61.4.
On press of the icon in the header on the right i want to move the 'ProfileScreen'. All the other navigation is working fine. I have a button in 'HomeScreen' to move to 'ResultsScreen' but cannot go to 'ProfileScreen' from the header.
Here is snippet of my code
const Stack = createStackNavigator();
const App = () => {
return (
<SafeAreaView style={{ flex: 1 }}>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={
{
title: 'Home',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerRight: () => (
<Icon
onPress={() => navigate('ProfileScreen')}
name="edit"
type="material"
/>
),
}
}
/>
<Stack.Screen
name="ResultsScreen"
component={ResultsScreen}
/>
<Stack.Screen
name="ProfileScreen"
component={ProfileScreen}
/>
</Stack.Navigator>
</NavigationContainer>
</SafeAreaView>
)
}
options can take a function as an argument and this function takes props as a parameter.
Here is the documentation
Here is the TypeScript definition for information:
* Navigator options for this screen.
*/
options?: ScreenOptions | ((props: {
route: RouteProp<ParamList, RouteName>;
navigation: any;
}) => ScreenOptions);
as you can see props, contain the navigation object that you can use to call navigate like this :
options={({ navigation }) => ({
title: 'Home',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerRight: () => (
<Icon
onPress={() => navigation.navigate('ProfileScreen')}
name="edit"
type="material"
/>
),
})}
Adding to Kevin's answer, you can also add a simple button in the header:
options={({ navigation }) => ({
title: 'Home',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerRight: () => (
<Button // a button in the header!
onPress={() =>
navigation.navigate('Account')}
title="Account"
/>
),
})}
Here is what worked for me:
<Stack.screen
name="YourScreenName"
headerShown=true
options={({ navigation }) => ({
title: 'YourOtherScreenName',
headerRight: () => (
<TouchableOpacity
onPress={() => navigation.dispatch(StackActions.push('articleEdit', {articleId: 'new'}))} >
<View style={SomeStyleWithPaddingYouLike}>
<JSX_That_Renders_Your_Icon />
</View>
</TouchableOpacity>
),
})}
/>