React Native: bottom tab press not working - javascript

in my react-native app I have a bottom tabs navigation, I added a tabPress listener to one of the screens but for some reason now all screens don't work, I can't navigate to a different screen when I tap the icons...
The objective was to lock a screen depending of the day but now ALL screens are locked for some reason and I can't navigate to ANY screen!
<Tab.Navigator /* options here... */>
<Tab.Screen name="Descubre" component={STACK1} />
<Tab.Screen name="Favoritos" component={STACK2}
listeners={{
tabPress: (e) => {
if(root.mapStore.isoWeekDay == 6)
{
e.preventDefault();
}
},
}}
/>
<Tab.Screen name="Pedidos" component={STACK3} />
<Tab.Screen name="Más" component={STACK4}/>
</Tab.Navigator>

I'm guessing this is the default behaviour stablished by React Native for this event, check section Listening to events​
If you want only to block one of the screens in this point, you could do the following:
<Tab.Navigator>
<Tab.Screen name="Screen 1" />
<Tab.Screen name="Screen 2"
options={{
tabBarButton: disabled ? DisabledTabBarButton : EnabledTabBarButton,
}}
/>
</Tab.Navigator>
Where DisabledTabBarButton is:
const DisabledTabBarButton = ({ style, ...props }: BottomTabBarButtonProps) => (
<Pressable disabled style={[{ opacity: 0.2 }, style]} {...props} />
)
And enabled one:
const EnabledTabBarButton = ({ style, ...props }: BottomTabBarButtonProps) => (
<Pressable style={[{ opacity: 1 }, style]} {...props} />
)
Also, you could do the following while creating your tab navigator:
const TabNavigator = createBottomTabNavigator({
First:{
screen: First,
},
Second:{
screen: Second,
},
Third:{
screen: Third,
}
}, defaultNavigationOptions: ({ navigation }) => ({
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (
navigation.state.routeName === "Route disabled"
) {
return null;
}
defaultHandler();
},})

Related

My tab navigation header button doesnt working. How can I fix it?

I'm trying to learn react native and I have a problem. Here I use tab navigation and I want to add an image in my headers right side and when the users touch that image I want use navigator, but it doesn't work.
import React, { useEffect, useState } from 'react'
import { View, StyleSheet, Image, TouchableOpacity } from 'react-native'
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs'
import { createStackNavigator } from '#react-navigation/stack';
const TabNavigation = ({ navigation }) => {
return (
enter code here
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
headerTitle: () => (<Image source={require('../Images/Floody.png')} />),
headerStyle: {
height: 100
},
headerTitleAlign: 'center',
headerRight: () => (
<TouchableOpacity>
<Image source={require('../Images/profile.jpg')} />
</TouchableOpacity>
),
tabBarIcon: ({ focused }) => focused ? <HomeImageColorfull /> : <HomeImageBlack />
}} />
The navigation object is passed by the navigation framework to the options of the screen. Hence, you can implement a onPress function for your TouchableOpacity of your headerRight component and use the navigation object from the options.
<Tab.Screen
name="Home"
component={HomeScreen}
options={({navigation}) => ({
headerTitle: () => (<Image source={require('../Images/Floody.png')} />),
headerStyle: {
height: 100
},
headerTitleAlign: 'center',
headerRight: () => (
<TouchableOpacity onPress={() => navigation.navigate("SomeScreenToNavigateTo")}>
<Image source={require('../Images/profile.jpg')} />
</TouchableOpacity>
),
tabBarIcon: ({ focused }) => focused ? <HomeImageColorfull /> : <HomeImageBlack />
})} />

React Native tab navigator nested in stack navigator

I'm relatively new to React Native and am struggling with screens. I've gone through the nested navigation documentation (https://reactnavigation.org/docs/nesting-navigators/) which helped me setup the initial nav setup i have, but im having some issues.
I'm attempting to setup the app so it has the initial screen as a "Select User" which has no tab navigation. After selecting the user, you are redirected to a another screen which has tab navigation. I currently have it working however I am unable to access any route/props/params after the initial screen.
I've had to manually import navigation with import { useNavigation } from "#react-navigation/native"; and even though I'm providing params in the Navigation.push, trying to access {route} in my screens states that route is undefined.
My setup of the screens looks similar to below:
const Tab = createBottomTabNavigator();
const WelcomeStack = createStackNavigator();
const HomeStack = createStackNavigator();
const SettingsStack = createStackNavigator();
const Stack = createStackNavigator();
const WelcomeStackScreen = () => (
<WelcomeStack.Navigator>
<WelcomeStack.Screen
name="Welcome"
component={WelcomeScreen}
options={{ headerShown: false }}
/>
<WelcomeStack.Screen
name="SignUp"
component={SignUpScreen}
options={{ headerShown: false }}
/>
</WelcomeStack.Navigator>
);
const HomeStackScreen = () => {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen
name="Search"
component={SearchResultScreen}
options={({ navigation }) => ({
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen
name="Select"
component={SelectScreen}
options={({ navigation, route }) => ({
title: route.params.name,
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen name="Read" component={ReaderScreen} />
</HomeStack.Navigator>
);
};
function SettingsScreen() {
return (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<Text>TBD</Text>
</View>
);
}
const SettingsStackScreen = () => (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
</SettingsStack.Navigator>
);
const TabNavigator = ({ route }) => (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
switch (route.name) {
case "Home":
iconName = focused ? "home" : "home-outline";
break;
case "Settings":
iconName = focused ? "list" : "list-outline";
break;
default:
break;
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: "tomato",
inactiveTintColor: "gray",
}}
>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsScreen}/>
</Tab.Navigator>
);
export default function App() {
return (
<NavigationContainer theme={navThemeOverride}>
<Stack.Navigator>
<Stack.Screen name="Welcome" component={WelcomeStackScreen} />
<Stack.Screen
name="TabNavigator"
component={TabNavigator}
options={{ headerShown: false }}
navigationOptions={{ gesturesEnabled: false }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Below is a snippet from the Welcome screen navigation
navigation.push("TabNavigator", {
screen: "Home",
params: {
userId: userId,
},
});
Your Home screen you're trying to navigate to from your parent-tab-navigator ... is also a StackNavigator ... and you wanna navigate to Select screen I guess ... so there's an extra level needed for your navigation to work...
navigation.navigate('TabNavigator', {
screen: 'Home', // <--- StackNavigator
params: {
screen: 'Select', // <-- nested inside HomeStack
params: {
title: 'Your custom title for Select screen here ...',
},
},
});
Plus +
There's a double definition for route in your Tab navigator
const TabNavigator = ({ route }) => ( //<--- here
<Tab.Navigator
screenOptions={({ route }) => ({ // <- and here
Instead
function TabNavigator() {
return <Tab.Navigator screenOptions={({ route }) => ({})>{/* ...Tabs... */}</Tab.Navigator>;
}

React Native Navigation v5 triggering a drawer from bottom tabs

Currently I am trying to tigger the drawer from the bottom nav as you can see here:
My current tabs is the following:
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused }) => {
let iconName;
switch (route.name) {
case 'Home':
iconName = 'window-maximize';
break;
case 'Purchases':
iconName = 'tags';
break;
case 'Notifications':
iconName = 'bell';
break;
case 'Checkout':
iconName = 'shopping-cart';
break;
case 'Orders':
iconName = 'dollar';
break;
case 'Menu':
iconName = 'navicon';
break;
}
return (
<Icon
name={iconName}
size={20}
color={focused ? 'blue' : 'grey'}
/>
);
},
})}
tabBarOptions={{
showLabel: false,
}}>
<Tab.Screen name="Home" component={LandingScreens} />
<Tab.Screen name="Purchases" component={PurchasesScreens} />
<Tab.Screen name="Notifications" component={Notifications} />
<Tab.Screen name="Checkout" component={CheckoutScreens} />
<Tab.Screen name="Orders" component={OrdersScreens} />
<Tab.Screen
name="Menu"
component={Drawer}
listeners={({ navigation }) => ({
tabPress: (e) => {
e.preventDefault();
},
})}
/>
</Tab.Navigator>
</NavigationContainer>
And my Drawer Component is just going to be a custom Drawer component:
const Drawer = ({ navigation }) => {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Home" component={LandingScreens} />
</Drawer.Navigator>
);
};
My question is something like this possible? I was trying to tigger the navigation.openDrawer() from the tabPress but couldn't find the method. I am doing this right, or would I need some sort of custom bottomNav? Any help is much appreciated!
Thanks.
You can either use DrawerActions.openDrawer:
import { DrawerActions } from '#react-navigation/native'
<Tab.Screen
name="Menu"
component={Drawer}
listeners={({ navigation }) => ({
tabPress: (e) => {
e.preventDefault();
navigation.dispatch(DrawerActions.openDrawer())
},
})}
/>
A better solution is to nest the tabs inside the drawer so navigation.openDrawer() works.
https://reactnavigation.org/docs/nesting-navigators#navigator-specific-methods-are-available-in-the-navigators-nested-inside

Header title not changing with bottom navigation React Native Navigation v5

so I 've got nested navigation, as the code shows. Now I am trying to make the header bar. however, when I change the screens from bottom navigation the header remains the same, no matter on what screen I am(always shoes that I am on Browser screen). Also is the React navigation header the best to create a header bar or is better to create a fully custom one. Thank you
I am expecting that the header title will change in accordance with the page.
const Stack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const AuthStack = createStackNavigator();
const TabsScreen = () => (
<Tabs.Navigator shifting={true} initialRouteName="Home" activeColor="#fff">
<Tabs.Screen
name="Home"
component={Browser}
options={{
tabBarLabel: 'Home',
tabBarColor: '#009387',
tabBarIcon: ({color}) => (
),
}}
/>
<Tabs.Screen
name="Sleep"
component={Sleep}
options={{
tabBarLabel: 'Sleep',
tabBarColor: '#694fad',
tabBarIcon: ({color}) => (
),
}}
/>
<Tabs.Screen
name="Settings"
component={SettingWithContext}
options={{
tabBarLabel: 'Settings',
tabBarColor: '#694fad',
tabBarIcon: ({color}) => (
),
}}
/>
</Tabs.Navigator>
);
export default CreateStack = () => {
const [isLoading, setIsLoading] = React.useState(true);
const [userToken, setUserToken] = React.useState(null);
const authContext = React.useMemo(() => {
return {
signIn: () => {
setIsLoading(false);
setUserToken('asdf');
},
signUp: () => {
setIsLoading(false);
setUserToken('asdf');
},
signOut: () => {
setIsLoading(false);
setUserToken(null);
},
};
}, []);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
if (isLoading) {
return ;
}
return (
<AuthContext.Provider value={authContext}>
{userToken ? (
<Stack.Navigator initialRouteName={Browser}>
<Stack.Screen name="Browser" component={TabsScreen} />
<Stack.Screen name="PreScreen" component={PreScreen} />
<Stack.Screen name="Player" component={Player} />
</Stack.Navigator>
) : (
<AuthStack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={RegisterLogin}>
<AuthStack.Screen name="RegisterLogin" component={RegisterLogin} />
<AuthStack.Screen name="Login" component={LoginWithContext} />
<AuthStack.Screen name="Register" component={RegisterWithContext} />
</AuthStack.Navigator>
)}
</AuthContext.Provider>
);
};
If you want to have every tab name to be the top try this: https://reactnavigation.org/docs/screen-options-resolution/
Check out the getHeaderTitle function and the switch statement below that - it helped me achieve this behavoir.
Because you are using nested navigation, and the stack navigator is the parent one, the top header will remain the same for any navigator inside the TabNavigator.
You might want to create instead a stack navigator inside each tab, so each tab will have its own header title and navigation path.
In another hand, you could try using screen options in order to create some business logic to determine which title you want based on the navigation state.
For example:
const Stack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const AuthStack = createStackNavigator();
const TabsScreen = () => (
<>
<Tabs.Navigator shifting={true} initialRouteName="Home" activeColor="#fff">
<Tabs.Screen
name="Home"
component={Browser}
options={{
tabBarLabel: "Home",
tabBarColor: "#009387",
tabBarIcon: ({ color }) => color,
}}
/>
<Tabs.Screen
name="Sleep"
component={Sleep}
options={{
tabBarLabel: "Sleep",
tabBarColor: "#694fad",
tabBarIcon: ({ color }) => color,
}}
/>
<Tabs.Screen
name="Settings"
component={SettingWithContext}
options={{
tabBarLabel: "Settings",
tabBarColor: "#694fad",
tabBarIcon: ({ color }) => color,
}}
/>
</Tabs.Navigator>
</>
);
let CreateStack = () => {
const [isLoading, setIsLoading] = React.useState(true);
const [userToken, setUserToken] = React.useState(null);
const authContext = React.useMemo(() => {
return {
signIn: () => {
setIsLoading(false);
setUserToken("asdf");
},
signUp: () => {
setIsLoading(false);
setUserToken("asdf");
},
signOut: () => {
setIsLoading(false);
setUserToken(null);
},
};
}, []);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
if (isLoading) {
return;
}
return (
<AuthContext.Provider value={authContext}>
{userToken ? (
<Stack.Navigator initialRouteName={Browser}>
{/* Added the options prop to the Browser screen*/}
<Stack.Screen
name="Browser"
component={TabsScreen}
options={({ route }) => ({
headerTitle: getHeaderTitle(route),
})}
/>
<Stack.Screen name="PreScreen" component={PreScreen} />
<Stack.Screen name="Player" component={Player} />
</Stack.Navigator>
) : (
<AuthStack.Navigator
screenOptions={{ headerShown: false }}
initialRouteName={RegisterLogin}
>
<AuthStack.Screen name="RegisterLogin" component={RegisterLogin} />
<AuthStack.Screen name="Login" component={LoginWithContext} />
<AuthStack.Screen name="Register" component={RegisterWithContext} />
</AuthStack.Navigator>
)}
</AuthContext.Provider>
);
};
/**
* Method to get the route name based on the component.
*/
const getHeaderTitle = (route) => {
if (route === "Browser") {
return "Home";
} else if (route === "Sleep") {
return "Sleep"
} else if (route === "Settings") {
return "Settings";
} else {
return route;
}
}
export default CreateStack;
The header is a thing in the stack navigation, not however in the tab-navigation.
Your App is using the header of the stack-navigator in which the tab-navigator is nested.
You could nest stack navigators inside your Tab-Navigator to have the header change as you need it to.

React Native - React Navigation Tab Bar - Custom floating action button

I need some help to use React Native - react navigation library.
It is Tab bar, but the Upload button acted as floating action button.
I have try :
const click = () => {
console.log('click');
return (
<View>
<Text>a</Text>
</View>
);
};
tabBarOnPress: (tab) => {
click();
},
// Main Page Navigator
export const Main = TabNavigator({
Home: {
screen: HomeNavigator,
},
Explore: {
screen: ExploreNavigator,
},
Upload: {
screen: UploadMain,
navigationOptions: ({ navigation }) => ({
tabBarLabel: 'Upload',
tabBarIcon: ({ tintColor }) => (
<View>
<Icon name="camera" size={26} color={tintColor} />
</View>
),
tabBarOnPress: (tab) => {
click();
},
}),
},
}, {
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
backBehavior: 'none',
swipeEnabled: false,
lazy: true,
animationEnabled: false,
showIcon: true,
tabBarOptions: {
activeTintColor: 'black',
},
});
The Upload button is need to act as floating action button, when it clicked, it already logging, but not rendering the component.
Any workaround to create the floating action button?
I've some tricks like this https://github.com/react-navigation/react-navigation/pull/1335
But, it is only click and dispatch navigation, not doing floating action button
Regards,
Charlie
you should write this code to your component!
-- you can use ‘react-native-tab-navigator' --
import TabNavigator from 'react-native-tab-navigator';
...
render(){
// console.log('TabRouter this.state:',this.state);
let tabs = [<Home {...this.props}/>,<Chat {...this.props}/>,<Web {...this.props}/>,<User {...this.props}/>];
let a = this.state.loginData.tabList.map((item,key)=>{
// console.log('item:',item);
return(
<TabNavigator.Item
key={key}
selected={this.state.selectedTab === item.type}
title={item.name}
renderIcon={() => <Image source={{uri:item.iconUnselectedUrl}} style={{width:24,height:24,}}/>}
renderSelectedIcon={() => <Image source={{uri:item.iconSelectedUrl}} style={{width:24,height:24}} />}
badgeText={this.state.tabBadge}
onPress={() => this.setState({
selectedTab: item.type,
tabBadge:0,
})}
>
{tabs[key]}
</TabNavigator.Item>
)
});
// console.log('a:',a);
return(
<TabNavigator
hidesTabTouch={true}
sceneStyle={{backgroundColor:'#fff'}}>
{a[0]}
{a[1]}
<TouchableOpacity
key={'add'}
style={{}}
renderIcon={() => <View style={{borderRadius:5,backgroundColor:'#46aee3',
width:width/5,height:49,justifyContent:'center',alignItems:'center'}}>
<Text style={{fontSize:49,padding:0,color:'#ffffff',backgroundColor:'rgba(0,0,0,0)'}}>+</Text></View>}
onPress={()=>this.props.navigation.navigate('SendBlog')}
/>
{a[2]}
{a[3]}
</TabNavigator>
)
}
...
-- update 2018/01/22 --
I think you should
let that;
class UploadMain extends Component {
constructor(props){
super(props);
that = this;
this.state = {
change:false,
};
}
changeState = () => {
this.setState({change:!change});
};
navigationOptions: ({ navigation }) => ({
tabBarLabel: 'Upload',
tabBarIcon: ({ tintColor }) => (
<View>
{that.state.change ? <Text>loading...</Text>:<Icon name="camera" size={26} color={tintColor} />}
</View>
),
tabBarOnPress: () => {
that.changeState;
},
}),
render(){
return (
<View>
....
</View>
)
}
}
If you are using react-navigation version 5.x, you should use tabBarButton to modify.
the code detail you can read
https://medium.com/#my.maithi/react-native-navigation-add-custom-button-in-the-middle-of-tabbar-6c390201a2bb
Hope can help you.

Categories

Resources