React Navigation 5 Header Options - react-native

How Do I set the Header right property on the <Stack.Navigator> ? I tried it with screenOptions but it is not rendering the headerRight Content on the right of header. I could set it on the parent Navigation Component which is rendering this custom component but in there I am not able to access the navigation prop. Could anyone please help me? Thank You
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen options={options3} name="SellerStackNavigator"
component={SellerStackNavigator} />
</Stack.Navigator>
</NavigationContainer>
const SellerStack = createStackNavigator();
const SellerStackNavigator = ({ navigation, route }) => {
<SellerStack.Navigator
screenOptions={({ route, navigation }) => ({
headerRight: () => (
<View style={{
flexDirection: 'row',
marginRight: 10,
}}>
<TouchableOpacity style={{
backgroundColor: '#fff',
borderRadius: 20,
marginRight: 10,
marginTop: 10,
height: 40,
width: 40,
alignItems: 'center',
justifyContent: 'center',
elevation: 2,
paddingLeft: 10,
}}>
<Image style={{
resizeMode: 'contain',
alignSelf: 'center',
borderWidth: 1,
marginRight: 10,
tintColor: '#000',
width: 15,
height: 18,
}} source={Images.searchImage}/>
</TouchableOpacity>
</View>
)
})}>
.
.
.
.
.
</SellerStack.Navigator>
}

I used more or less your code and is working for me, so if you can make a expo I can check what is really happening https://snack.expo.io/#anthowm/headerright
Anyways you can accesss your navigation from anywhere with useNavigation hook
function MyBackButton() {
const navigation = useNavigation();
return (
<Button
title="Back"
onPress={() => {
navigation.goBack();
}}
/>
);
}
You can do access to it
<NavigationContainer>
{(route, navigation) => {
return <Stack.Navigator>
<Stack.Screen options={options3} name="SellerStackNavigator"
component={SellerStackNavigator} />
</Stack.Navigator>}}
</NavigationContainer>

Related

Blank screen when I put Drawer Navigator as the main navigator in index.tsx

If I put Drawer Navigator in index.tsx I only get a blank screen.
Tried wrapping NavigationContainer in index.tsx in a View with flex: 1 but it didn't work.
Also I don't have alignItems: 'center' in App.tsx to remove as this answer suggests. (https://stackoverflow.com/a/62647417/13117660)
index.tsx:
const Drawer = createDrawerNavigator();
export const store = configureStore({});
export default () => {
return (
<Provider store={store}>
<DatabaseConnectionProvider>
<NavigationContainer>
<Drawer.Navigator drawerContent={(props: any) => <CustomDrawerContent {...props} />} screenOptions={{
headerTitle: () => <Image source={require('../assets/logo_navbar.jpg')} style={{
width: 120,
height: 40,
alignContent: 'center'
}} />,
headerTitleAlign: 'center',
headerStyle: {
backgroundColor: Colors.RED,
}
}} >
<Drawer.Screen name='Home' component={HomeScreen}></Drawer.Screen>
</Drawer.Navigator>
</NavigationContainer>
</DatabaseConnectionProvider>
</Provider>
);
};
CustomDrawerContent.tsx:
const CustomDrawerContent: FC = (props: any) => {
return (
<View style={{ flex: 1, backgroundColor: Colors.RED }}>
<DrawerContentScrollView {...props} style={styles.drawerContent2}>
<View style={styles.drawerContent}>
<Drawer.Section style={styles.drawerSection}>
<DrawerItem
labelStyle={{ color: Colors.WHITE, fontSize: 20, marginLeft: 20 }}
label={"Home"}
onPress={() => {
props.navigation.navigate("Home");
}}
/>
<DrawerItem
labelStyle={{ color: Colors.WHITE, fontSize: 20, marginLeft: 20 }}
label={"About us"}
onPress={() => {
props.navigation.navigate("AboutUs");
}}
/>
<DrawerItem
labelStyle={{ color: Colors.WHITE, fontSize: 20, marginLeft: 20 }}
label={"Impresum"}
onPress={() => {
props.navigation.navigate("Impresum");
}}
/>
<DrawerItem
labelStyle={{ color: Colors.WHITE, fontSize: 20, marginLeft: 20 }}
label={"Contact"}
onPress={() => {
props.navigation.navigate("Contact");
}}
/>
</Drawer.Section>
</View>
</DrawerContentScrollView>
</View>
);
};
export default CustomDrawerContent;
const styles = StyleSheet.create({
drawerContent: {
flex: 1,
backgroundColor: Colors.RED,
},
drawerContent2: {
flex: 1,
},
labels: {
fontSize: 30,
},
userInfoSection: {
paddingLeft: 20,
},
title: {
fontSize: 16,
marginTop: 3,
fontWeight: "bold",
},
caption: {
fontSize: 14,
lineHeight: 14,
},
row: {
marginTop: 20,
flexDirection: "row",
alignItems: "center",
},
section: {
flexDirection: "row",
alignItems: "center",
marginRight: 15,
},
paragraph: {
fontWeight: "bold",
marginRight: 3,
},
drawerSection: {
marginTop: 15,
fontWeight: "bold",
backgroundColor: Colors.RED,
},
});
Edit:
Also when I use the Drawer Navigator like this in index.tsx it also shows just blank screen
return (
<Provider store={store}>
<DatabaseConnectionProvider>
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name='Home' component={HomeScreen}></Drawer.Screen>
<Drawer.Screen name='About' component={AboutUsScreen}></Drawer.Screen>
</Drawer.Navigator>
</NavigationContainer>
</DatabaseConnectionProvider>
</Provider>
);
When I put a breakpoint on the return of HomeScreen component it gets hit only the first time the app loads, but nothing renders on screen. If I reload the app than the HomeScreen breakpoint is not hit. I have to stop the server and run the app again every time. But the blank screen is always there.
If I change the Drawer Navigatior to Stack Navigatior than everything works. But I need the Drawer Navigator to be the main navigator.
I am using expo, #react-navigation/drawer 6.3.0 and #react-navigation/native 6.0.8
So I found out what wasn't working. My debbuger was on and it was causing problems as explained here: https://github.com/react-navigation/react-navigation/issues/10253
I am debugging in VS code, not in Chrome Debugger but still when I turn off debugging it works. If the debugger is on you have to put
useLegacyImplementation={false}
as a prop in Drawer.Navigator. It is little laggy but works.
I am using react-native-reanimated 2.4.0

Globally accessible variable to control Bottom Tab Navigator in React Native app

I am using createBottomTabNavigator from #react-navigation/bottom-tabs to make a nice bottom navigation for my application. I have added some custom notification indicators for the tab bar icons, that illustrates "news" inside the specific stacks. These icons (dots) should be visible if a variable is true and otherwise the dot shoul be hidden. The variable will be depending on the content of the stack so if there are new messages in the MessagesStack, the unread_messages = true and so on...
I am looking for a solution where I can access these variables in my TabStack from the specific stacks, so when I call the API in the MessagesStack and there is a new message, I can update unread_messages in the TabStack and show the dot.
I have pasted the full code for my TabStack in the App.js-file below:
TabStack = () => {
StatusBar.setBarStyle("dark-content");
const insets = useSafeAreaInsets();
return (
<View style={main_Styles.mainBackground}>
<View style={{ flex: 1, paddingBottom: insets.bottom,}} >
<View style={{ flex: 1}} >
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconOpacity = (focused) ? 1.0 : 0.2;
let iconSize = 28;
if (route.name === 'HomeStack') {
return (
<View style={{alignItems: 'center'}}>
<Icon name='home_white' size={iconSize} opacity={iconOpacity}/>
</View>
);
}
if (route.name === 'MessagesStack') {
return (
<View style={{alignItems: 'center'}}>
<Icon name='messages_white' size={30} opacity={iconOpacity}/>
{((unread_messages ?? 0) > 0) && <View style={{backgroundColor: Main.colours.yellow_medium, width: 6, height: 6, borderRadius: 3}} />}
</View>
);
}
if (route.name === 'GroupsStack') {
return (
<View style={{alignItems: 'center'}}>
<Icon name='group_white' size={iconSize} opacity={iconOpacity}/>
</View>
);
}
if (route.name === 'NotificationsStack') {
return (
<View style={{alignItems: 'center'}}>
<Icon name='notifications_white' size={iconSize} opacity={iconOpacity}/>
{((unread_notifications ?? 0) > 0) && <View style={{backgroundColor: Main.colours.yellow_medium, width: 6, height: 6, borderRadius: 3, marginTop: 1}} />}
</View>
);
}
if (route.name === 'MyProfileStack') {
return (
<View style={{alignItems: 'center'}}>
<View style={{marginTop: 3, flexDirection: 'row', width: 24, height: 24, borderRadius: 12, opacity: iconOpacity, borderColor: Main.colours.red_light, borderWidth: 0, overflow: 'hidden'}}>
<ProfileImage style={{flex: 1, backgroundColor: 'red'}} image_url={this.state.profile_image_url} initials={this.state.initials}/>
</View>
{(pending_friend_requests > 0 || pending_event_applications > 0 || pending_group_applications > 0 ) && <View style={{backgroundColor: Main.colours.yellow_medium, width: 6, height: 6, borderRadius: 3, marginTop: 2}} />}
</View>
)
}
},
headerShown: false,
lazy: false,
optimizationsEnabled: false,
animationEnabled: true,
activeTintColor: Main.colours.white,
showIcon: true,
swipeEnabled: Platform.OS === 'ios' ? true : false,
tabBarShowLabel: false,
scrollEnabled: true,
tabBarStyle: {
backgroundColor: Main.colours.red_medium,
borderTopWidth: 0,
shadowOpacity: 0,
elevation: 0,
paddingTop: 0,
paddingBottom: 0,
height: 49,
},
tabBarIndicatorStyle: {
backgroundColor: 'transparent',
},
})}>
<Tab.Screen name="HomeStack" component={HomeStack} />
<Tab.Screen name="MessagesStack" component={MessagesStack}/>
<Tab.Screen name="GroupsStack" component={GroupsStack}/>
<Tab.Screen name="NotificationsStack" component={NotificationsStack} />
<Tab.Screen name="MyProfileStack" component={MyProfileStack} />
</Tab.Navigator>
</View>
</View>
</View>
);
}
Here, there are three solutions for updating icons in the tab
First, create Tab Icon as a functional component and then you can bind
the API with redux, and once redux is updated, it will update the tab
icon component, use redux context
Use global app context.
for eg. create one state in the main app context and update that context
once your API call is done so it will automatically update your tab
component
fire local notification and update date the tab component(not
recommended)

Is there any way I can place the TabBar over my header

I had an idea in my design but making it proved harder than I thought. The design is as follows:
The tabbar here is made with 'createMaterialTopTabNavigator'.
My idea was that the gradient part will be the header so it won't move when navigating from INFO to PHOTOS. I am able the screen the way it looks in the picture above except for the TopTabNavigator overlapping the header. It looks as follows:
I do understand why this is happening since the topTabNavigator is inside of the stackNavigator and thus the header will always be on top. The thing is that I want the gradient part to stay in place when swiping left or right through the topTabNavigator.
The profile Stack Screen:
const ProfileStackScreen = ({ navigation }) => {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={ProfileTabScreen} options={{
header: () => ( <ProfileHeader onPress={() => {navigation.openDrawer()}} />)
}} />
</ProfileStack.Navigator>
);
};
The header:
const ProfileHeader = (props) => {
return (
<LinearGradient colors={[color1, color2]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={{
width: '100%,
alignItems: 'center',
paddingVertical: 50,
}}>
<View style={{width: '100%}}>
<View style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 20,
width: '100%',
}}>
<TouchableOpacity><Icon /></TouchableOpacity>
<TouchableOpacity><Text>Edit profile</Text></TouchableOpacity>
</View>
</View>
<Image style={{height: 115, width: 115, borderRadius: 100}} source={require('../path/img.jpg')} />
</LinearGradient>
);
}

How can i update or pass badge count from component to Tab.Navigator. React-native

I want to update or show the badge count in bottom tabs, how can I pass count from API in Component to Tab.Navigator and display the count in the bottom tabs.
sample code
`import Channels from '#channels';
import Documents from '#documents';
render(){
return(
<Tab.Navigator
initialRouteName={this.state.selectedTab}
tabBarOptions={{
activeTintColor: '#248E42',
labelStyle:{fontSize:width/35'}
}}
>
<Tab.Screen
name="Channels"
component={Channels}
options={{
tabBarLabel: 'Channels',
tabBarIcon: ({ focused,badgeCount }) => (
<View>
<Image source={Images.iconChannel} style={{ height: 24, width: 24 }} />
{badgeCount < 0 &&
(
<View style={styles.badge}>
<Text style={{ color: 'white', fontSize: 10, fontWeight: 'bold' }}>{badgeCount}</Text>
</View>
)
}
</View>
)
}}
/>
<Tab.Screen
name="Documents"
component={Documents}
options={{
tabBarLabel: 'Documents',
tabBarIcon: ({ focused }) => (
<Image source={Images.iconDocuments} style={{ height: 24, width: 24 }} />
),
}}
/>
</Tab.Navigator>)}
`
Your Environment
`#react-navigation/native - ^5.1.7
#react-navigation/bottom-tabs - ^5.2.8
react-native-screens - ^2.7.0
react-native - 0.62.2`
I was also having this problem for my notifications badge in bottom tabs. So, I made tabbarIcon a separate component and connected it with app state.
class BottomTabIcon extends Component {
render() {
const { color, notifications: { data: notifications } } = this.props;
const badgeCount = _.filter(notifications, notification => !notification.is_read).length;
return (
<View style={{ width: 24, height: 24, margin: 5 }}>
<Image source={images.bottom_notification} style={{ tintColor: color }} />
<View
style={{
position: 'absolute',
right: -6,
top: -3,
backgroundColor: 'red',
padding: 3,
borderRadius: 6,
// width: 12,
// height: 12,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text style={{ color: 'white', fontSize: 10, fontWeight: 'bold' }}>
{badgeCount}
</Text>
</View>
</View>
);
}
}
const mapStateToProps = state => ({
notifications: state.notifications
})
export default connect(mapStateToProps)(BottomTabIcon);
Then Imported the component to use as tabbarIcon.
<Tab.Navigator
initialRouteName={this.state.selectedTab}
tabBarOptions={{
activeTintColor: '#248E42',
labelStyle:{fontSize:width/35'}
}}
>
<Tab.Screen
name="Channels"
component={Channels}
options={{
tabBarLabel: 'Channels',
tabBarIcon: (props) => <BottomTabIcon {...props} />
)
}}
/>
</Tab.Navigator>
This solution worked for me, I hope this solves your problem also
I connected the whole TabNavigator and passed the needed properties.

How to add clients logo on bottom Tab Bar

i am creating an android based mobile app using react native. I want to add a logo on my bottom tab. The tab bar also contains 4 tabs. I need to display a logo on left corner of my device. Logo is not a clickable one, just an image.
For React Navigation 5.
You can show custom BottomTabBar with tabBar options.
Define Tab stack
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator tabBar={props => <BottomTabBar {...props} />}>
<Tab.Screen name="Tab1" component={Screen3} />
<Tab.Screen name="Tab2" component={Screen2} />
<Tab.Screen name="Tab3" component={Screen2} />
<Tab.Screen name="Tab4" component={Screen2} />
</Tab.Navigator>
);
}
Create Custom BottomTabBar
import React from 'react';
import {View,Text,Image,Platform,TouchableOpacity,StyleSheet} from 'react-native';
const BottomTabBar = ({state, navigation, ...props}) => {
const {routes = [], index: activeIndex} = state;
return (
<View style={styles.container}>
<Image
source={require('../../assets/logo.png')}
style={styles.imageIcon}
/>
<View style={styles.tabContainer}>
{routes.map((it, index) => {
return (
<TouchableOpacity
onPress={() => {
navigation.jumpTo(it.name);
}}
style={[
styles.tabButton,
{
borderBottomWidth: activeIndex === index ? 1 : 0,
},
]}>
<Text>{it.name}</Text>
</TouchableOpacity>
);
})}
</View>
</View>
);
};
export default BottomTabBar;
const styles = StyleSheet.create({
tabButton: {
flex: 1,
height: 50,
justifyContent: 'center',
alignItems: 'center',
borderBottomColor: 'red',
},
tabContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-evenly',
},
imageIcon: {
width: 50,
height: 50,
resizeMode: 'contain',
},
container: {
width: '100%',
flexDirection: 'row',
alignItems: 'center',
height: 64,
paddingHorizontal: 16,
backgroundColor: 'white',
paddingBottom: Platform.OS === 'ios' ? 15 : 0,
},
});
ScreenShot