I have a project that has stack and tab navigation in it. There is a strange problem it in which is: The tabs and screens are not touchable sometimes, although the screen is always scrollable is there is any ScrollView in that screen.
Note: The project was running fine for last 2 years but I recently(last month) migrated from mac intel to mac m1 chip using migration assistant.
This problem started appearing from the last week.
The Structure of the Project:
The Screen MainScreen is imported and called in app.js
MainScreen checks for the token and calls MainNavigation, which is
another screen
In MainNavigation I have 4 tabs like <Tab.Screen name="Dashboard"
component={DashboardStack}/>
Used import {createBottomTabNavigator} from
'#react-navigation/bottom-tabs'
Then there are 4 other screens each one for one tab like:
DashboardStack
Used import {createStackNavigator} from '#react-navigation/stack'
And inside DashboardStack file, I have all the files that will be for
Dashboard
Package.json
"react": "16.13.1",
"react-native": "0.63.4",
"#react-navigation/bottom-tabs": "^5.11.2",
"#react-navigation/native": "^5.8.10",
"#react-navigation/stack": "^5.12.8",
"react-native-safe-area-context": "^3.4.1",
"react-native-screens": "^2.16.1",
MainNavigation screen
function DashboardStack({navigation, route}) {
return <DashboardNavigation navigation={navigation} route={route} driverId={driverId} globalSettings={props.globalSettings} handleLogout={props.handleLogout}/>
}
return(
<NavigationContainer>
<Tab.Navigator tabBarOptions={{ showLabel: false, style:{bottom:5}}}
screenOptions={({route}) => ({tabBarIcon: ({focused}) => handleNavIcon(route.name, focused)})}
>
<Tab.Screen name="Dashboard" component={DashboardStack}/>
<Tab.Screen name="Billing" component={BillingStack} />
<Tab.Screen name="Rental" component={RentalStack} />
<Tab.Screen name="Support" component={SupportStack} />
<Tab.Screen name="Account" component={AccountStack} />
</Tab.Navigator>
</NavigationContainer>
)
DashboardNavigation.js
<DashboardStack.Navigator options={{ headerShown: true, }} screenOptions={{ headerBackTitleVisible: false, headerTitleAlign: "center", headerRight: () => <NotificationIcon driverId={props && props.driverId && props.driverId} navigation={props.navigation}/> }}>
<DashboardStack.Screen name="Dashboard" children={() => <Dashboard driverId={props.driverId} globalSettings={props.globalSettings} handleLogout={props.handleLogout} />} />
<DashboardStack.Screen name="Current Documents" component={carDocs} options={{ headerBackImage: () => <MaterialIcons size={Platform.OS == "ios" ? 30 : 25} name="arrow-back" style={{ paddingLeft: 10 }} /> }}></DashboardStack.Screen>
<DashboardStack.Screen name="Notifications" component={NotificationListScreen} options={{ headerBackImage: () => <MaterialIcons size={Platform.OS == "ios" ? 30 : 25} name="arrow-back" style={{ paddingLeft: 10 }} /> }}></DashboardStack.Screen>
<DashboardStack.Screen name="Notification Detail" component={NotificationDetailScreen} options={{ headerBackImage: () => <MaterialIcons size={Platform.OS == "ios" ? 30 : 25} name="arrow-back" style={{ paddingLeft: 10 }} /> }}></DashboardStack.Screen>
<DashboardStack.Screen name="Under Construction" component={ComingSoon} options={{ headerBackImage: () => <MaterialIcons size={Platform.OS == "ios" ? 30 : 25} name="arrow-back" style={{ paddingLeft: 10 }} /> }}></DashboardStack.Screen>
<DashboardStack.Screen name="Make a Payment" component={makePayment} options={{ headerBackImage: () => <MaterialIcons size={30} name="arrow-back" style={{ paddingLeft: 10 }} /> }}></DashboardStack.Screen>
<DashboardStack.Screen name="Verify Phone Number" component={VerifyPhoneNumber} options={{ headerBackImage: () => <MaterialIcons size={30} name="arrow-back" style={{ paddingLeft: 10 }} /> }}></DashboardStack.Screen>
</DashboardStack.Navigator>
Related
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
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'}
/>
),
}} />
The initial navigation works fine, but when I press return or press the same tab (to go back), the app is closed.
I use React Navigation v6+ and navigators like Stack and Material Bottom Tabs.
Main Navigation
<Tab.Navigator
initialRouteName='TabMovie'
activeColor="#f0edf6"
keyboardHidesNavigationBar={true}
inactiveColor="#000000"
shifting={true}
barStyle={{
borderWidth: 0,
elevation: 0,
height: (Platform.OS == 'ios') ? 80 : 54
}}
>
<Tab.Screen
name="TabMovie"
component={TabMovie}
options={{
tabBarLabel: 'Cine',
tabBarColor: '#EC9B45',
tabBarIcon: (({ color }) => (
<Icon color={color} size={25} name="videocam-outline" />
))
}}
/>
<Tab.Screen
name="TabsTvShow"
component={TabsTvShow}
options={{
tabBarLabel: 'TV Shows',
tabBarColor: '#58149C',
tabBarIcon: (({ color }) => (
<Icon color={color} size={25} name="desktop-outline" />
))
}}
/>
<Tab.Screen
name="TabTopRated"
component={TabTopRated}
options={{
tabBarLabel: 'Top Rated',
tabBarColor: '#135990',
tabBarIcon: (({ color }) => (
<Icon color={color} size={25} name="star-half-outline" />
))
}}
/>
<Tab.Screen
name="TabSearch"
component={TabSearch}
options={{
tabBarLabel: 'Search',
tabBarColor: '#A62349',
tabBarIcon: (({ color }) => (
<Icon color={color} size={25} name="search-outline" />
))
}}
/>
</Tab.Navigator>
One of stack navigators
<Stack.Navigator
initialRouteName='HomeScreen'
screenOptions={{
headerShown: false,
cardStyle: {
backgroundColor: 'white'
}
}}
>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="MovieDetailScreen" component={MovieDetailScreen} />
</Stack.Navigator>
Another stack navigator
<Stack.Navigator
initialRouteName="TvShowsScreen"
screenOptions={{
headerShown: false,
cardStyle: {
backgroundColor: 'white'
}
}}
>
<Stack.Screen name="TvShowsScreen" component={TvShowsScreen} />
<Stack.Screen name="TvShowDetailScreen" component={TvShowDetailScreen} />
</Stack.Navigator>
I use the navigation hook to navigate between views, and i do not have any button to return. I hope to use the button return that each mobile has, and the nativation tab (material tab button) to return to the previous view
This is a shared component when I use the navigation
<TouchableOpacity
onPress={() => navigation.navigate('MovieDetailScreen', movie)}
activeOpacity={0.95}
style={{ width, height, ...moviePosterStyles.card }}>
<View style={moviePosterStyles.imageContainer}>
<Image
source={
(poster_path)
? { uri }
: require('../assets/images/no-movie.jpg')
}
style={moviePosterStyles.image}
/>
</View>
</TouchableOpacity>
Screen where I press return
<ScrollView>
<View style={detailStyles.imageContainer}>
<View style={detailStyles.imageBorder}>
<Image
source={{ uri }}
style={detailStyles.posterImage}
/>
</View>
</View>
<View style={detailStyles.titlesContainer}>
<Text style={detailStyles.subTitle}>{original_title}</Text>
<Text style={detailStyles.title}>{title}</Text>
</View>
<MovieDetails movieFull={movieFullDetails!} cast={cast} similarMovies={similarMovies!} />
</ScrollView>
Package.json
"dependencies": {
"#react-native-masked-view/masked-view": "^0.2.7",
"#react-navigation/material-bottom-tabs": "^6.2.3",
"#react-navigation/native": "^6.0.11",
"#react-navigation/stack": "^6.2.2",
"axios": "^0.27.2",
"intl": "^1.2.5",
"react": "18.0.0",
"react-native": "0.69.3",
"react-native-gesture-handler": "^2.5.0",
"react-native-image-colors": "^1.3.1",
"react-native-linear-gradient": "^2.6.2",
"react-native-paper": "^4.12.4",
"react-native-reanimated": "^2.9.1",
"react-native-reanimated-carousel": "^3.0.3",
"react-native-safe-area-context": "^4.3.1",
"react-native-screens": "^3.15.0",
"react-native-snap-carousel": "^1.3.1",
"react-native-splash-screen": "^3.3.0",
"react-native-vector-icons": "^9.2.0",
"react-native-webview": "^11.23.0",
"react-native-youtube-iframe": "^2.2.2"
},
There is no have a problem with the navigation.
I use a package: react-native-youtube-ifram to show YouTube videos, and the component was needs an additional attr
<YoutubePlayer
videoId={trailerYoutubeKey}
playList={trailersYoutubeList}
height={screenDimensions * 0.30}
webViewStyle={{ opacity: 0.99 }} // This attr
/>
Now, the navigation works correctly
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.
I want to set a dynamic initialRouteName on my TabNavigator (not even sure if this is the right place to do it), let me explain more clearly.
I have a BottomTabNavigator with 4 items : Home (HomeStack), Explorer (ExplorerStack), subscriptions (SubscribeStack) & contact (contactStack). When the app load, with the token I was redirecting the user to my MainNavigator (so my BottomTabNavigator) with the initialRouteName Home.
<Stack.Navigator headerMode="none">
{!token ? (
<Stack.Screen
isSignout={isSignout}
name="AuthStack"
component={AuthNavigator}
/>
) : (
<Stack.Screen name="HomeStack" component={MainNavigator} />
)}
</Stack.Navigator>
What I want to do now is : when the user is not null and have no subscriptions I want to redirect him directly to the Explorer Tab and not the Home Tab.
// MainNavigator.js
const MainNavigator = (props) => {
const [loading, setLoading] = useState(true);
const [subs, setSubs] = useState([]);
const [fetchData, {data: meData}] = useLazyQuery(USER_ME_QUERY);
useEffect(() => {
fetchData();
if (meData) {
setSubs(meData.me.subscribes);
setLoading(false);
}
}, [meData]);
if (loading) {
return <Loading />;
}
return (
<Tab.Navigator
initialRouteName={subs.length > 0 ? 'Home' : 'Explorer' }
tabBarOptions={{
shadowColor: 'transparent',
showLabel: false,
style: {
backgroundColor: dark ? theme.color.secondary : theme.color.white,
elevation: 0, // for Android
borderTopColor: dark ? '#46505C' : theme.color.lightBorder,
},
}}>
<Tab.Screen
name="Home"
component={HomeStack}
options={{
tabBarIcon: ({focused}) =>
focused ? (
<Icon size={22} name="home" color={theme.color.primary} />
) : (
<Icon size={22} name="home" color={theme.color.lightGrey} />
),
}}
/>
<Tab.Screen
name="Explorer"
component={ExplorerStack}
options={{
tabBarIcon: ({focused}) =>
focused ? (
<Icon size={22} name="columns" color={theme.color.primary} />
) : (
<Icon size={22} name="columns" color={theme.color.lightGrey} />
),
}}
/>
<Tab.Screen
name="Subscribe"
component={SubscribeStack}
options={{
tabBarIcon: ({focused}) =>
focused ? (
<Icon size={22} name="sliders" color={theme.color.primary} />
) : (
<Icon size={22} name="sliders" color={theme.color.lightGrey} />
),
}}
/>
<Tab.Screen
name="Contact"
component={ContactStack}
options={{
tabBarIcon: ({focused}) =>
focused ? (
<Icon size={22} name="mail" color={theme.color.primary} />
) : (
<Icon size={22} name="mail" color={theme.color.lightGrey} />
),
}}
/>
</Tab.Navigator>
);
};
export default MainNavigator;
Is there a simple way to achieve this ? Any help would be appreciated x
If you need more infos, feel free to ask :)
Thanks in advance x