React native - remove space between drawerIcon and item text on Drawer.Screen - react-native

I'm trying to adjust space between icon and text in drawer screen.
Here's an image to explain better.
Here's my code
<Drawer.Navigator screenOptions={(navigation) => ({
drawerItemStyle: {
borderRadius: 0,
width: '100%',
marginLeft: 0
}
})}>
<Drawer.Screen
name="HomeScreen"
component={HomeScreen}
options={{
headerShown: true,
headerTransparent: true,
headerTitle: "",
title: 'Start Delivery',
drawerIcon: (({focused}) => <Icon name="car" size={25} color={focused ? "#288df9" : "#777"} style={{padding:0, margin:0}} />)
}}
/>
</Drawer.Navigator>
Thanks

The default Drawer uses a DrawerItemList which is a list of DrawerItems. Looking at the source code, the view that wraps the label implements a marginLeft of 32. This is hardcoded and cannot be changed without using dirty tricks.
Let us test this using the following example.
function App() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} options={{drawerIcon: () => <View style={{height:20, width: 20, backgroundColor: "red"}} />}} />
</Drawer.Navigator>
</NavigationContainer>
);
}
The above uses a View as a dummy image with a red background. Here is the result.
Adding a marginRight of -32 to our icon removes the "gap" completely.
function App() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} options={{drawerIcon: () => <View style={{height:20, width: 20, backgroundColor: "red", marginRight: -32}} />}} />
</Drawer.Navigator>
</NavigationContainer>
);
}
Here is the result.
This is not ideal since we have to do this for each icon, thus we could create a custom component and reuse it.
const CustomIconComponent = ({focused, name}) => {
return <View style={{marginRight: -32}}>
<Icon name={name} size={25} color={focused ? "#288df9" : "#777"} />
</View>
}
Then, use it for each screen.
options={{
...
title: 'Start Delivery',
drawerIcon: (({focused}) => <CustomIconComponent focused={focused} />)
}}
There is a second way. We could create a custom drawer. This would allow us to not use the DrawerItem component but a custom component with custom stylings.

Related

Turning off the drawer header in a specific screen in bottom tab navigation in drawer navigation in react native

I have a very big problem I am using two navigations in one app the first one is the drawer navigator this is how I use the drawer navigator:
<Drawer.Navigator
screenOptions={{
drawerStyle: {
backgroundColor: 'white',
},
}}
drawerContent={props => <CustomSidebarMenu {...props} />}
drawerContentOptions={{
activeTintColor: '#e91e63',
activeBackgroundColor: 'red',
itemStyle: {marginVertical: 20},
}}>
<Drawer.Screen
options={{
headerShown: true,
headerTitle: () => (
<Image
style={{height: 150, width: 100, resizeMode: 'contain'}}
source={require('../assets/images/referans2.png')}
/>
), // Title to appear in the header
headerRight: ({navigation, scene}) => (
// Custom component to appear on the right side of the header
<View style={{flexDirection: 'row'}}>
<Pressable>
<Ionicons
name="notifications-outline"
size={30}
color={'black'}
/>
</Pressable>
<Pressable style={{marginHorizontal: 10}}>
<Ionicons
name="chatbubbles-outline"
size={30}
color={'black'}
/>
</Pressable>
</View>
),
}}
name="Ana Sayfa"
component={Main}
/>
<Drawer.Screen
options={{headerShown: true}}
name="Şiparişlerim"
component={MyOrders}
/>
<Drawer.Screen name="Adreslerim" component={AddressesScreen} />
<Drawer.Screen name="Üyelik Bilgilerim" component={AccountInfoScreen} />
</Drawer.Navigator>
[
and this gives me the following output:](https://i.stack.imgur.com/73o8f.png)
In the main function you see here, the bottomtabnavigator, which I use in the whole app, returns.:
const Main = () => {
return (
<Tab.Navigator screenOptions={screenOptions}>
<Tab.Screen
component={HomeStack}
name="Ana Sayfa"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="home-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={CategoriesStack}
name="Kategoriler"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="grid-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={CartStack}
name="Sepet"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="cart-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={DiscoverStack}
name="Keşfet"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="compass-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={ProfileStack}
name="Profilim"
options={{
headerShown: true,
tabBarIcon: ({focused, color}) => (
<Ionicons name="person-circle-outline" size={28} color={color} />
),
}}
/>
</Tab.Navigator>
);
};
What I want is this; Turning off the header of the drawer in the profile stack in the bottom tab navigator, but I can't do it
but it still didn't close the header of the drawer navigation. Even if I set the headershown of the drawer to false, the header on all screens closes, I'm just not on the screen I want
As far as I understand, there are 3 nested navigator.
Drawer
|---------> BottomTab
| |---------> ProfileStack
|... |...
If you want to hide or show only specific screen you can use navigation.setOptions()
For example,we have a Profile screen in ProfileStack and get navigation with screen props or useNavigation()
If you want to hide ProfileStack header in Profile:
React.useLayoutEffect(() => {
navigation.setOptions({ headerShown:false })
})
If you want to hide BottomTab header in Profile:
React.useLayoutEffect(() => {
navigation.getParent().setOptions({ headerShown:false })
})
If you want to hide Drawer header in Profile:
React.useLayoutEffect(() => {
navigation.getParent().getParent().setOptions({ headerShown:false })
})
You can use setOptions with headerShown:true when the drawer screenOptions headerShown:false
react-navigation getParent() and setOptions() docs

How to add clickable Icons to reactNative navbar

I want to add clickable icons to my reactnative header component
Currently it looks like this
next to the title text on the right I want to add an audio symbol but i cant figure out on doing this.
I have seen plenty of answers that work with navigation but Im using drawers so i dnt understand how to add icons.
This is what my code looks like
app.js
<NavigationContainer >
<Drawer.Navigator initialRouteName="MetalDetector" screenOptions={{
drawerStyle: {
backgroundColor: '#3e4463',
width: 220
},
}}>
<Drawer.Screen name="MetalDetector" component={Home} options={{drawerLabel: '🔦 MetalDetector'}} />
<Drawer.Screen name="Settings" component={Settings} options={{drawerLabel: '🛠 Settings'}} />
<Drawer.Screen name="Calibrate" component={Home} options={{drawerLabel: '💡 Calibration'}}/>
<Drawer.Screen name="Feedback" component={Home} options={{drawerLabel: '👨‍👩‍👧‍👦 Feedback'}}/>
and this is my home.js file which renders content for the metaldetector page
<View style={styles.container}>
<View style={styles.buttonContainer}>
//Cde is below
</View>
</View>
);
}
So where would i add icons to the titlemenu?
I found this here, which covers on how to set the header using stackscreen
https://reactnavigation.org/docs/headers/
but since I use drawer.screen i dont know how to apply that
Option 1:
The DrawerContent file
import React, { useState } from 'react';
import { View, StyleSheet, Image, Alert, Text } from 'react-native';
import { Title, Drawer } from 'react-native-paper';
import { DrawerContentScrollView, DrawerItem } from '#react-navigation/drawer';
import { FontAwesome, MaterialIcons, AntDesign, Ionicons } from '#expo/vector-icons';
import colors from '../config/colors';
const AppDrawerItem = ({ label , icon, onPress, ...props }) => {
return (
<DrawerItem
icon={icon}
label={label}
onPress={onPress}
/>
);
}
export function DrawerContent(props) {
return (
<View style={{ flex: 1 }}>
<DrawerContentScrollView {...props}>
<Drawer.Section style={styles.drawerSection}>
<AppDrawerItem
onPress={() => { setIsDeletePressed(false); props.navigation.navigate('Dashboard') }}
label="Dashboard"
icon={({ color, size, focused }) => (
<MaterialIcons
name="dashboard"
color={focused ? colors.primary : color}
size={size}
/>
)}
{...props}
/>
<AppDrawerItem
onPress={() => { setIsDeletePressed(false); props.navigation.navigate('Messages') }}
label="Messages"
icon={({ color, size, focused }) => (
<MaterialIcons
name="notifications"
color={focused ? colors.primary : color}
size={size}
/>
)}
{...props}
/>
</Drawer.Section>
</DrawerContentScrollView >
</View >
);
}
DrawerNavigator
<Drawer.Navigator
screenOptions={{
headerTitleStyle: {
color: "black",
opacity: 0.9
},
headerTintColor: colors.primary,
swipeEnabled: false,
headerTitleAlign: 'center',
headerShadowVisible: false,
}} drawerContent={props => <DrawerContent {...props} />} > //---here you can add drawercontent component
<Drawer.Screen name="Dashboard" component={HomeScreen} />
<Drawer.Screen options={{ headerShown: true }} name="Messages" component={NotificationNavigator} />
</Drawer.Navigator >
Edit:
Option2:
You can add the icon in the <Drawer.Screen> tag.
<Drawer.Screen name="Feed" component={Feed} options={{
title: 'Home',
drawerIcon: ({focused, size}) => (
<Ionicons
name="md-home"
size={size}
color={focused ? '#7cc' : '#ccc'}
/>
),
}} />

React-navigation - goBack behaviour in nested navigators (stack inside drawer)

I'm using a stack navigator inside drawer navigator - recently upgraded from v4. Trying to implement custom back button on headerLeft. goBack function on the stack screen is going back on the drawer navigator instead of the stack. I don't know if I'm missing something or if it's a bug on v5. The goBack should go to the previous screen in the stack not the drawer. See the gif below; using the gesture goes back on the stack and the default back button on the header goes back onto the stack too. It's only my custom back button with the problem.
export function BlogsStack({navigation}) {
return (
<Stack.Navigator
initialRouteName={'Blogs'}
screenOptions={{
gestureEnabled: true,
gestureDirection: 'horizontal',
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
headerStyle: {
borderBottomWidth: 0,
elevation: 0,
shadowOpacity: 0,
},
headerTintColor: themeVars.headerTintColor,
headerBackground: () => {
return <HeaderBackground />;
},
}}>
<Stack.Screen
name="Blogs"
component={Blogs}
options={{
title: 'Blogs',
headerTitle: () => (
<View>
<HeaderButton title={'Blogs'} />
</View>
),
headerLeft: () => (
<TouchableOpacity
onPress={() => navigation.toggleDrawer()}
style={drawerStyles.menuIconContainer}>
<FeatherIcon
style={drawerStyles.menuIcon}
name="menu"
size={themeVars.hamburgerIconSize}
color={themeVars.hamburgerIconColor}
/>
</TouchableOpacity>
),
headerRight: () => <View />,
}}
/>
<Stack.Screen
name="BlogSingle"
component={BlogSingle}
options={{
headerTitle: () => (
<View>
<HeaderButton title={'Blog'} />
</View>
),
headerLeft: () => (
<TouchableOpacity
onPress={() => navigation.goBack()}
style={drawerStyles.menuIconContainer}>
<FeatherIcon
style={drawerStyles.menuIcon}
name="chevron-left"
size={themeVars.hamburgerIconSize}
color={themeVars.hamburgerIconColor}
/>
</TouchableOpacity>
),
headerRight: () => <View />,
}}
/>
</Stack.Navigator>
);
}
export class Navigation extends Component {
constructor(props, context) {
super(props, context);
}
render() {
return (
<NavigationContainer ref={navigationRef}>
<AppDrawer.Navigator
initialRouteName={'Home'}
drawerContent={props => <DrawerContent {...props} />}
drawerContentOptions={{
labelStyle: {
fontFamily: themeVars.boldFont,
color: themeVars.primaryColor,
},
activeTintColor: 'black',
activeBackgroundColor: 'black',
inactiveTintColor: 'white',
inactiveBackgroundColor: 'white',
itemStyle: {
marginVertical: 0,
borderWidth: 1,
borderColor: 'red',
margin: 0,
padding: 0,
},
}}>
<AppDrawer.Screen
name="Home"
component={HomeStack}
initialRouteName={'Home'}
options={{
drawerLabel: 'Home ',
drawerIcon: () => (
<FeatherIcon
color={themeVars.primaryColor}
name="home"
size={themeVars.drawerIconSize}
/>
),
}}
/>
<AppDrawer.Screen
initialRouteName="Blogs"
backBehavior="order"
name="Blogs"
component={BlogsStack}
options={{
drawerLabel: 'Blogs ',
drawerIcon: () => (
<FontAwesome5
color={themeVars.primaryColor}
name="wordpress"
size={themeVars.drawerIconSize}
/>
),
}}
/>
</AppDrawer.Navigator>
</NavigationContainer>
);
}
}
I sorted out my issue by following the docs. The issue was that I was passing the wrong navigation.
You need to use the correct navigation prop in your header, i.e. by
defining a callback for the options:
https://reactnavigation.org/docs/screen-options#options-prop-on-screen
You're using navigation prop passed from the parent navigator which is
a drawer, so the action is performed in the drawer.
Follow the git issue: https://github.com/react-navigation/react-navigation/issues/8806
To be more clear : we have to get the navigation prop from specific screen itself hence the screen stack will be notified of the history. using hook doesn't do this.

Reversing tab navigator direction to support RTL react navigation

I have been trying to change the tab direction to RTL instead of LTR. Unfortunately, I cannot find out how it works. I used flextDirection in tabBarStyle or style props as "row" or "row-reverse", but when I did so, the whole tab was removed. It only appeared when using column or column-reverse showing at the top or bottom of the screen. Here is my code:
const Tab = createMaterialBottomTabNavigator();
<Tab.Navigator
activeColor={theme.colors.text}
inactiveColor={theme.colors.textAlt}
barStyle={{
backgroundColor: theme.colors.background,
flexDirection: "row-reverse", //In this case an empty tab bar only appears with no screens. Screens only appear when it changes to column
}}
shifting={true}
screenOptions={defaultNavOptions}>
<Tab.Screen
name={userConfig.appTexts.homeScreenName}
component={AppNavigator}
options={{
tabBarIcon: ({ color, size }) => {
return <Ionicons name="ios-home" color={color} size={22} />;
},
}}
initialParams={{ theme, taxonomy }}
/>
<Tab.Screen
name={userConfig.appTexts.settingScreenName}
component={SettingNavigator}
options={{
tabBarIcon: ({ color, size }) => {
return <Ionicons name="ios-settings" color={color} size={22} />;
},
}}
initialParams={{ theme }}
/>
<Tab.Screen
name={userConfig.appTexts.savedScreenName}
component={PostNavigator}
options={{
tabBarIcon: ({ color, size }) => {
return <Ionicons name="md-bookmark" color={color} size={22} />;
},
}}
initialParams={{ saved: true, theme }}
/>
</Tab.Navigator>
I guess you can change style in the tabBarOptions :
<Tab.Navigator
tabBarOptions={{
style: {transform: [{scaleX: -1}]},
}}> {Your}
</Tab.Navigator>
Simply reverse your Tab screens order inside Tab Navigator. So move the last screen to be the first and...

Custom header component in React-Native vesion 0.63 (Confusion in the documentation of React-Native Naviagtion)

I have been reading the document for React-Native Navigation. In the section for header bar configuration, it gives an example to render a custom header like so:
function LogoTitle() {
return (
<Image
style={{ width: 50, height: 50 }}
source={require('#expo/snack-static/react-native-logo.png')}
/>
);
}
function StackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerTitle: props => <LogoTitle {...props} /> }}
/>
</Stack.Navigator>
);
}
I am having confusion with **options={{ headerTitle: props => <LogoTitle {...props} /> }}** what props are being passed to the LogoTitle component?
Only props that are relevant to the headerTitle option. To find out, add a console.log() to the following, and check the console.log.
function LogoTitle(props) {
console.log('props = ', props);
return (
<Image
style={{ width: 50, height: 50 }}
source={require('#expo/snack-static/react-native-logo.png')}
/>
);
}