Reversing tab navigator direction to support RTL react navigation - react-native

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...

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

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

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.

React native v6: tab bar customization

i have a bottom tab in my react native application, when i try to edit the tabBarStyle on the tab navigator it doesnt work. It only works on 1 out of my 3 tabs for some reason.
Only the help tab follows the required design the home and the test tab remain as default. I have tried all solutions only add made sure that i am using screenOptions and tabBarStyle instead of style.
const Tab = createBottomTabNavigator();
const AppNavigator = () => {
return (
<Tab.Navigator
screenOptions={{
tabBarActiveTintColor:'white',
tabBarLabelStyle:{
fontWeight:'700'
},
tabBarStyle: {
backgroundColor:'black',
borderTopColor: 'black',
elevation: 0, // for Android
shadowOffset: {
width: 0, height: 0 // for iOS
},
height:Platform.OS==='ios'&& dimen.width>400?80:Platform.OS==='ios'&& dimen.width<400?60:50,
}
}}
initialRouteName={"Home"}
>
<Tab.Screen
name="Home"
component={HomeNavigator}
options={{
tabBarIcon: ({ size, color,focused }) => (
<Entypo name="home" size={30} color={'#969696'}/>
),
headerShown:false,
unmountOnBlur: true,
}}
/>
<Tab.Screen
name="Test"
component={TestNavigator}
options={({ navigation }) => ({
tabBarButton: () => (
<NewListingButton
onPress={() => navigation.navigate(routes.test)}
/>
),
tabBarIcon: ({ size, color }) => (
<FontAwesome
name="life-saver"
size={size}
color={color}
/>
),
headerShown: false,
unmountOnBlur: true,
})
}
/>
<Tab.Screen
name="Help"
component={HelpNavigator}
options={{
tabBarIcon: ({ size, color,focused }) => (
<Ionicons name="help" size={30} color={'#969696'}/>
),
unmountOnBlur: true,
headerShown:false,
}}
/>
</Tab.Navigator>
)
};
export default AppNavigator;
My problem was with react navigation 6 in order to hide the tab navigator on specific screens i had to set the tabBarStyle display to none, which was why the background wasnt changing if the tab had a stack

Stack nested inside Material Bottom Tab dont show the content when you navigate the second time (React Navigation v6)

Problem:
When I navigate to the Stack inside the Material Bottom the first time, all works fine, after that you change tab and when you return the content don't render any more.
Expected behavior:
Every time you select the tab the Stack must be render. In other words, I am able to see the content of the Stack inside the Tab every time I navigate to the Tab.
package
version
#react-navigation/native
6.0.6
#react-navigation/material-bottom-tabs
6.0.9
#react-navigation/native-stack
6.2.5
react-native-safe-area-context
3.3.2
react-native-screens
3.8.0
react-native
0.64.2
expo
43.0.0
Faced the same problem.
Found solution here: https://github.com/software-mansion/react-native-screens/issues/1197#issuecomment-993682256
You should wrap your nested navigator with a View that has collapsable false.
Example with my code:
const MealsNavigator = () => (
<NavigationContainer>
<TabNavigator />
</NavigationContainer>
)
const TabNavigator = () => (
<Tab.Navigator initialRouteName="Meals" {...TabProps} >
<Tab.Screen name="Meals" component={StackNavigator} options={{ headerShown: false, tabBarIcon: ({ color }) => (<Ionicons name='ios-restaurant' size={24} color={color} />), tabBarColor: Colors.primaryColor }} />
<Tab.Screen name="Favorites" component={FavoritesScreen} options={{ tabBarIcon: ({ color }) => (<Ionicons name='ios-star' size={24} color={color} />), tabBarLabel: 'Favorites!', tabBarColor: Colors.accentColor }} />
</Tab.Navigator>
)
const StackNavigator = () => (
<View style={{ flex: 1 }} collapsable={false}>
<Stack.Navigator initialRouteName="Categories" screenOptions={{
headerStyle: { backgroundColor: Platform.OS === "android" ? Colors.primaryColor : '' }, headerTintColor: Platform.OS === "android" ? 'white' : Colors.primaryColor
}} >
<Stack.Screen name="Categories" component={CategoriesScreen} options={{ title: 'Meal Categories' }} />
<Stack.Screen name="CategoryMeals" component={CategoryMealsScreen} options={({ route }) => ({ title: route.params.title })} />
<Stack.Screen name="MealDetail" component={MealDetailScreen} options={({ route }) => ({ title: route.params.title })} />
</Stack.Navigator>
</View>
)

How to send props from createBottomTabNavigation to every tab screen?

I am using createBottomTabNavigation and I have 4 screens which I can access by pressing the tab bar screen in the bottom of my screen. I am also using Stack Navigation to display the title of the screen there and also all screens have the same settings icon.
I could make the same function in every screen that takes care of onPress event on the Settings icon but that is repetitive and I don't want to do it.
My question is - is there a way for me to pass a function as a props from the App component which holds the bottom navigation to every screen?
App screen code:
<NavigationContainer >
<Tab.Navigator initialRouteName="Home" tabBarOptions={{
activeTintColor: '#FF9F0A',
inactiveTintColor:'white',
style: {
backgroundColor:'#000000',//color you want to change
borderTopWidth: 0,
paddingTop:5,
paddingBottom:5,
},
}}>
<Tab.Screen name="Home" component={Home} options={{
tabBarLabel: 'HOME',
tabBarIcon: ({ color, size }) => (
<HomeTabIcon name="home" color={color} size={size} />
),
}}/>
<Tab.Screen name="Controls" component={Controls} options={{
tabBarLabel: 'CONTROLS',
tabBarIcon: ({ color, size }) => (
<ControlsTabIcon name="controls" color={color} size={size} />
),
}}/>
<Tab.Screen name="Charging" component={Charging} options={{
tabBarLabel: 'CHARGING',
tabBarIcon: ({ color, size }) => (
<ChargingTabIcon name="charging" color={color} size={size}/>
),
}}/>
Charging screen:
function Charging() {
return (
<View style={globalStyles.container}>
<Text>Charging</Text>
<StatusBar style="auto" />
</View>
);
}
export default function ChargingStackScreen() {
return (
<ChargingStack.Navigator>
<ChargingStack.Screen name="CHARGING" component={Charging} options={{
headerRight: () => (
<View style={globalStyles.headerRight}>
<SettingsIcon />
</View>
),
headerTitleAlign:'left',
headerTintColor: 'white',
headerTitleStyle: globalStyles.headerTitle,
headerStyle: globalStyles.header
}}/>
</ChargingStack.Navigator>
);
}
So what I think you should do is have the header as a separate component, where you can use the useNavigation hook (assuming you're using the latest version of react-navigation), and have the settings button do the navigation you need. Then just render the header component once above the Tab.Navigator instead of rendering it on every screen.
Something like:
function Header(props){
const navigation = useNavigation();
// component code
<SettingsButton onPress={() => navigation.navigate(whatever)}/>
}
And then I am pretty sure (not 100% though) that you can render it in your NavigationContainer, something like:
<NavigationContainer >
<Header/>
<Tab.Navigator initialRouteName="Home" tabBarOptions={{
// rest of the code