Change tab bar button on different screen in Expo bottomTabNavigator - react-native

If have the following code :
const Tab = createBottomTabNavigator();
export default function Tabs() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
headerShown: false,
tabBarShowLabel: true,
tabBarHideOnKeyboard: true,
tabBarStyle: {
backgroundColor: "#FFFFFF",
height: "8%",
position: "absolute",
},
})}
>
<Tab.Screen
name="Home"
component={Home}
options={{
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#299ca4" : "#b5b5b5",
fontFamily: "Jost",
fontWeight: "600",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
ACCUEIL
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/home-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/home.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
<Tab.Screen
name="Explorer"
component={Explorer}
options={{
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#299ca4" : "#b5b5b5",
fontFamily: "Jost",
fontWeight: "600",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
MARCHES
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/explorer-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/explorer.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
<Tab.Screen
name="Scanner"
component={Scanner}
options={{
tabBarLabel: ({ focused }) => (
<Text
style={{
color: "#ffffff",
}}
>
SCANNER
</Text>
),
tabBarIcon: ({ focused }) => (
<View
style={{
width: 55,
height: 55,
backgroundColor: "#089baa",
borderRadius: 50,
marginBottom: 30,
justifyContent: "center",
alignItems: "center",
}}
>
<Image
source={require("../assets/scanner-blanc.png")}
style={{ width: 28, height: 28 }}
/>
</View>
),
}}
/>
<Tab.Screen
name="Community"
component={Community}
options={{
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#299ca4" : "#b5b5b5",
fontFamily: "Jost",
fontWeight: "600",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
FIL D'ACTU
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/news-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/news.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
<Tab.Screen
name="Profile"
component={Menu}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#299ca4" : "#b5b5b5",
fontFamily: "Jost",
fontWeight: "600",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
PROFIL
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/profile-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/profile.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
</Tab.Navigator>
);
}
If I am on any screen, the "Scanner" button in the center of the navigator displays the "Scanner" screen when pressed.
What I need to do is to render another button to display another view instead of it, if I am on a different screen.
For instance, if I am in the "Home" screen, I want the "Scanner" button, and if I am in the "Explorer" screen, I want the "Scanner" button be replaced with another one to call another screen.

Related

React Bottom Tab Navigation - Change the title in the screen without changing the title in the tab

I can change the Header Title dynamically but that changes the title in the tab as well.
How can I change the title on the screen without affecting the title in the tab?
This is my navigator -
<Tab.Screen
name="Lists"
component={Lists}
options={{
title: "Lists",
headerShown: true,
headerLeft: () => (
<Pressable
style={{ paddingLeft: 16 }}
onPressIn={() => console.log("Filter")}
hitslop={5}
>
<Ionicons name="filter" size={28} color={"#faf2c4"} />
</Pressable>
),
headerRight: () => (
<Pressable
style={{ paddingRight: 16 }}
onPressIn={() => console.log("Search")}
hitslop={5}
>
<Ionicons name="search" size={28} color={"#faf2c4"} />
</Pressable>
),
headerStyle: {
backgroundColor: "#0292b7",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
headerTitleStyle: {
color: "#faf2c4",
fontFamily: "Quicksand_600SemiBold",
},
headerTitleAlign: "center",
}}
/>
This is how I dynamically change the Title in the screen component -
const [Title, setTitle] = useState("noLists");
useEffect(() => {
navigation.setOptions({ title: Title });
}, []);
Use tabBarLabel in options:
<Tab.Screen
name="Lists"
component={Lists}
options={{
tabBarLabel:"Lists",
title: "Lists",
headerShown: true,
headerLeft: () => (
<Pressable
style={{ paddingLeft: 16 }}
onPressIn={() => console.log("Filter")}
hitslop={5}
>
<Ionicons name="filter" size={28} color={"#faf2c4"} />
</Pressable>
),
headerRight: () => (
<Pressable
style={{ paddingRight: 16 }}
onPressIn={() => console.log("Search")}
hitslop={5}
>
<Ionicons name="search" size={28} color={"#faf2c4"} />
</Pressable>
),
headerStyle: {
backgroundColor: "#0292b7",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
headerTitleStyle: {
color: "#faf2c4",
fontFamily: "Quicksand_600SemiBold",
},
headerTitleAlign: "center",
}}
/>

tabBarButton style not applying react-nav-6

I would like to change the styling of a main button. Although this code is not working. I would like the styling to not be affected by the nav bar height. Here is code
const CircleButton = ({ children, onPress }) => (
<TouchableOpacity onPress={onPress} style={{
top: -30,
justifyContent: 'center',
alignItems: 'center',
...style.shadow
}}>
<View style={{
width: 70,
height: 70,
borderRadius: 35,
backgroundColor: 'yellow',
}}>
{children}
</View>
</TouchableOpacity>
)
<bTabs.Navigator
screenOptions={{ tabBarLabel: false, }}
barStyle={{
position: 'absolute',
bottom: 25,
left: 20,
right: 20,
elevation: 0,
backgroundColor: theme.nav.backgroundColor,
borderRadius: 10,
height: 50,
...style.shadow
}}
>
<bTabs.Screen name="Create" component={CreateContent} options=
{{
tabBarIcon: ({ focused }) => (
<View>
<Icon name='plus' size={25} color={focused ? theme.mainColor : theme.secondaryBGColor} />
</View>
),
tabBarButton: (...props) => <CircleButton {...props} onPress={() => console.log('t')} />,
}}
/>
Also note i have tried using tabBarButton: (...props) => (<CircleButton {...props} onPress={() => console.log('t')} />), and with {}
Please ignore syntax. Thank you

Bottom tab bar : change screen from a component instead of pressing navigator button

I have a bottom tab navigator that works well.
It calls differents screens when pressing the buttons.
What I need to do is to call a screen from a component when I close it by pressing a button.
To add more details, consider that I have two screens (home and messenger).
When I am on the messenger screen, I open a component by pressing a button.
This component takes all the screen. When I close it, I would like to be "redirected" to the home screen directly, not the messenger one.
I work on Expo.
How can I achieve that ?
The navigator code :
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { Text, View, Image } from "react-native";
import News from "../screens/News";
import Explorer from "../screens/Explorer";
import Home from "../screens/Home";
import Scanner from "../screens/Scanner";
import Search from "../screens/Search";
import Publish from "../screens/Publish";
import Write from "../screens/Write";
import Messenger from "../screens/Messenger";
import { RFPercentage } from "react-native-responsive-fontsize";
import { DataContext } from "../components/Context";
import { useState, useContext, useEffect } from "react";
const Tab = createBottomTabNavigator();
export default function Tabs() {
const {
login,
screenName,
openRecharge,
openCollect,
openAskCash,
openTransfer,
openConvert,
menuPage,
notifModal,
} = useContext(DataContext);
console.log(login);
return (
<Tab.Navigator
screenOptions={({ route }) => ({
headerShown: false,
tabBarShowLabel: true,
tabBarHideOnKeyboard: true,
tabBarStyle: {
display:
login != 1 ||
openRecharge ||
openCollect ||
openAskCash ||
openConvert ||
openTransfer ||
notifModal ||
menuPage == "index" ||
menuPage == "profile"
? "none"
: "flex",
backgroundColor: "#FFFFFF",
height: "8%",
position: "absolute",
borderTopColor: "transparent",
elevation: login != 1 ? 0 : 20,
},
})}
>
<Tab.Screen
name="Home"
component={Home}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#373945" : "#75787d",
fontFamily: "Jost",
fontWeight: "700",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
ACCUEIL
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/home-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/home.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
<Tab.Screen
name="Explorer"
component={Explorer}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#373945" : "#75787d",
fontFamily: "Jost",
fontWeight: "700",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
MARCHÉS
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/explorer-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/explorer.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
{(() => {
switch (screenName) {
case "Home":
return (
<Tab.Screen
name="Scanner"
component={Scanner}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: "#ffffff",
}}
>
SCANNER
</Text>
),
tabBarIcon: ({ focused }) => (
<View
style={{
width: 55,
height: 55,
backgroundColor: "#089baa",
borderRadius: 50,
marginBottom: 30,
justifyContent: "center",
alignItems: "center",
}}
>
<Image
source={require("../assets/scanner-blanc.png")}
style={{ width: 28, height: 28 }}
/>
</View>
),
}}
/>
);
case "Explorer":
return (
<Tab.Screen
name="Search"
component={Search}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: "#ffffff",
}}
>
SEARCH
</Text>
),
tabBarIcon: ({ focused }) => (
<View
style={{
width: 55,
height: 55,
backgroundColor: "#089baa",
borderRadius: 50,
marginBottom: 30,
justifyContent: "center",
alignItems: "center",
}}
>
<Image
source={require("../assets/glass-white.png")}
style={{ width: 28, height: 28 }}
/>
</View>
),
}}
/>
);
case "News":
return (
<Tab.Screen
name="Publish"
component={Publish}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: "#ffffff",
}}
>
PUBLISH
</Text>
),
tabBarIcon: ({ focused }) => (
<View
style={{
width: 55,
height: 55,
backgroundColor: "#089baa",
borderRadius: 50,
marginBottom: 30,
justifyContent: "center",
alignItems: "center",
}}
>
<Image
source={require("../assets/add.png")}
style={{ width: 28, height: 28 }}
/>
</View>
),
}}
/>
);
case "Messenger":
return (
<Tab.Screen
name="Write"
component={Write}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: "#ffffff",
}}
>
MESSENGER
</Text>
),
tabBarIcon: ({ focused }) => (
<View
style={{
width: 55,
height: 55,
backgroundColor: "#089baa",
borderRadius: 50,
marginBottom: 30,
justifyContent: "center",
alignItems: "center",
}}
>
<Image
source={require("../assets/pencil.png")}
style={{ width: 28, height: 28 }}
/>
</View>
),
}}
/>
);
default:
return null;
}
})()}
<Tab.Screen
name="News"
component={News}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#373945" : "#75787d",
fontFamily: "Jost",
fontWeight: "700",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
FIL D'ACTUS
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/news-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/news.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
<Tab.Screen
name="Messenger"
component={Messenger}
options={{
unmountOnBlur: true,
tabBarLabel: ({ focused }) => (
<Text
style={{
color: focused ? "#373945" : "#75787d",
fontFamily: "Jost",
fontWeight: "700",
fontSize: RFPercentage(1.2),
marginTop: -10,
marginBottom: 10,
}}
>
MESSAGES
</Text>
),
tabBarIcon: ({ focused }) =>
focused ? (
<Image
source={require("../assets/messagerie-active.png")}
style={{ width: 20, height: 20 }}
/>
) : (
<Image
source={require("../assets/messagerie.png")}
style={{ width: 20, height: 20 }}
/>
),
}}
/>
</Tab.Navigator>
);
}
I faced the same issue before, this is how I solved it:
Created a global flag that changes to a specific value (example: 1) when I go to the target screen, in your case the Component which takes the whole screen
I perform a check in the Messenger screen in a useFocusEffect hook that if the flag is 1 redirect to the home screen and change the flag to 0
This way I can visit the Messenger screen again cause the value will be 0 but once I open the component it will change to 1 and once I press back I will be redirected to Home Screen
The useFocusEffect part:
import { useFocusEffect } from "#react-navigation/native";
export default function ConfirmOrder(){
useFocusEffect(
React.useCallback(() => {
if (cart.length == 0) {
navigation.navigate("Home");
}
})
);
return(
<Text>Confirm Order Page</Text>
)
}

TypeError: Cannot read property 'navigate' of undefined in the main App.js file

I am getting this error TypeError: Cannot read property 'navigate' of undefined. All code is defined in the main App.js file. Any solutions for this.
<Stack.Screen
name="Home"
component={BottomNav}
options={{
headerShown: true,
headerTitle: 'Home',
headerTitleStyle: { color: 'blue', fontWeight: 'bold' },
headerRight: () => (
<TouchableOpacity
activeOpacity={0.5}
onPress={() => this.props.navigation.navigate('PropertySearchScreen')}>
<Image
source={require('./../assets/icons/search.png')}
style={{ width: 25, height: 25, marginRight: 20 }}
/>
</TouchableOpacity>
),
}}
/>
Change your options of your navigator like this :
options={({navigation})=>{
headerShown: true,
headerTitle: 'Home',
headerTitleStyle: { color: 'blue', fontWeight: 'bold' },
headerRight: () => (
<TouchableOpacity
activeOpacity={0.5}
onPress={() => navigation.navigate('PropertySearchScreen')}>
<Image
source={require('./../assets/icons/search.png')}
style={{ width: 25, height: 25, marginRight: 20 }}
/>
</TouchableOpacity>
),
}}

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.