React Native mixed Navigation - react-native

I am about to crate an app that has a main Drawer Navigator (sidemenu). On some specific pages I want to add an additional Tabsmenu to the page. How can I achieve that?
This is the Drawer Navigator:
const Drawer = createDrawerNavigator()
function myLogout(){
navigation.navigate("LoginScreen");
}
const DrawerNavigator = () => {
// Load the icon font before using it
const [fontsLoaded] = useFonts({ IcoMoon: require('../../assets/icomoon/zepra_icons.ttf') });
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<Drawer.Navigator initialRouteName="Home" drawerContent={props => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="Logout" labelStyle={{marginLeft:-18, fontSize: 15,}}
icon={({ focused, color, size }) => <Icon2 style={{marginLeft:8}} color={focused ? '#1585b5' : '#6cbabf'} size={26} name={focused ? 'log-out-outline' : 'log-out-outline'} /> }
onPress={() => props.navigation.navigate("StartScreen") } />
</DrawerContentScrollView>
)
}}>
...
<Drawer.Screen name="Impressum" component={ImpressumStackNavigator}
options={{
drawerLabel: 'Impressum',
drawerLabelStyle:{marginLeft:-18, fontSize: 15,},
drawerIcon: ({focused, size}) => (
<Icon2 style={{marginLeft:7}} name='ios-information-circle-outline' size={26} color={focused ? '#1585b5' : '#6cbabf'} />
)}}/>
</Drawer.Navigator>
)
}
export default DrawerNavigator
this is the Dashboard Page:
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native'
import DrawerNavigator from './DrawerNavigator'
function App() {
return (
<DrawerNavigator />
);
}
export default App;
and this is the page with the tabs:
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import DrawerNavigator from './DrawerNavigator';
//#################### BUTTON-TAB erstellen #####################
const Tab = createBottomTabNavigator();
function MainContainer({ route, navigation }) {
//function MainContainer({ }) {
// Load the icon font before using it
const [fontsLoaded] = useFonts({ IcoMoon: require('../../assets/icomoon/zepra_icons.ttf') });
const { data } = route.params;
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<Tab.Navigator
initialRouteName={projectsName}
screenOptions={({ route }) => ({
headerShown: false,
tabBarIcon: ({ focused, color, size }) => {
let iconName;
let rn = route.name;
if (rn === projectsName) {
iconName = focused ? 'PROJEKTE_ALLE' : 'PROJEKTE_ALLE';
} else if (rn === waermeschutzName) {
iconName = focused ? 'HAUS_3' : 'HAUS_3';
} else if (rn === begehungenName) {
iconName = focused ? 'NOTIZ_ERSTELLEN' : 'NOTIZ_ERSTELLEN';
}
// You can return any component that you like here!
return <Icon name={iconName} size={43} color={color} />;
},
'tabBarActiveTintColor': '#4283b1',
'tabBarInactiveTintColor': '#5db8bd',
'tabBarStyle':{ 'paddingTop':4, 'height':90 },
'tabBarLabelStyle':{ 'paddingTop':3, 'fontSize':13 }
})}>
<Tab.Screen name={projectsName} component={ProjectsScreen} initialParams={{ data }} />
<Tab.Screen name={waermeschutzName} component={WaermeschutzScreen} />
<Tab.Screen name={begehungenName} component={BegehungenScreen} />
</Tab.Navigator>
);
}
export default MainContainer;
How can I add the DrawerNavigator to the Tabspage now?
Thank you for your help

Related

Blur on SearchBar doesn't occurs with Tab.Navigator

I have a Tab.Navigator made with createBottomTabNavigator and I'm trying to implement a SearchBar inside it. But the blur event never happen when I click outside the SearchBar.
It's working well when I submit the search action.
Here's my Tab.Navigator :
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import {HomeStack} from './home';
import {SearchStack} from './search';
import {AddStack} from './add';
import {NewsStack} from './news';
import {ProfileStack} from './profile';
import Ionicons from 'react-native-vector-icons/Ionicons';
import colors from '../styles/colors';
const Tab = createBottomTabNavigator();
export function MainStack(){
return (
<Tab.Navigator
initialRouteName="Home"
activeColor="#333"
inactiveColor="#333"
screenOptions={({ route }) => ({
tabBarIcon: ({ color, size }) => {
let iconName;
if (route.name === 'Accueil') {
iconName = 'compass-outline';
}
else if (route.name === 'Rechercher') {
iconName = 'search-outline';
}
else if (route.name === 'Ajouter') {
iconName = 'add-circle-outline';
}
else if (route.name === 'Actus') {
iconName = 'newspaper-outline';
}
else if (route.name === 'Profil') {
iconName = 'person-circle-outline';
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: colors.primaryColor,
tabBarStyle: {
paddingBottom: 5,
}
})}
>
<Tab.Screen name="Accueil" component={HomeStack} options={{headerShown:false}}/>
<Tab.Screen name="Rechercher" component={SearchStack} options={{headerShown:false}}/>
<Tab.Screen name="Ajouter" component={AddStack} options={{headerShown:false}}/>
<Tab.Screen name="Actus" component={NewsStack} options={{headerShown:false}}/>
<Tab.Screen name="Profil" component={ProfileStack} options={{headerShown:false}}/>
</Tab.Navigator>
);
}
And my SearchBar :
<SearchBar
lightTheme={ scheme === 'dark' ? false : true}
onSubmitEditing={() => submitSearch(0)}
onChangeText={updateSearch}
value={search}
placeholder="Rechercher"
round
containerStyle={{backgroundColor: 'transparent', borderTopWidth:0, borderBottomWidth:0}}
onCancel={() => {setResults([]); setSearch(''); setSearched(false); setSelectedIndex(0);}}
onClear={() => {setResults([]); setSearch(''); setSearched(false); setSelectedIndex(0);}}
/>

How to add a buttont that handle display of DrawerNav to TabNav

How to implement a buttom navigator that containt a button that handle DrawerNav display
To be able to do it, first you would have to add your custom tab bar, by overriding the tabBar property on the Tab.Navigator component. Here is an example from the official React Navigation docs.
Then you would have to add a button to your custom tab bar, which purpose would be to open the drawer screen (navigation.openDrawer).
Here's an example how you could do it:
import React from 'react';
import {
Button,
SafeAreaView,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createDrawerNavigator } from '#react-navigation/drawer';
const Tab = createBottomTabNavigator();
const TabItem = ({ label, onPress, isFocused = false }) => (
<TouchableOpacity
accessibilityRole="button"
onPress={onPress}
style={{
flex: 1,
padding: 20,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{ color: isFocused ? '#673ab7' : '#222' }}>{label}</Text>
</TouchableOpacity>
);
const MyTabBar = ({ state, descriptors, navigation }) => {
const focusedOptions = descriptors[state.routes[state.index].key].options;
if (focusedOptions.tabBarVisible === false) {
return null;
}
const onOpenDrawerPress = () => {
navigation.openDrawer();
};
return (
<View style={{ flexDirection: 'row' }}>
<TabItem label="Open drawer" onPress={onOpenDrawerPress} />
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
return (
<TabItem label={label} onPress={onPress} isFocused={isFocused} />
);
})}
</View>
);
};
const TabOneScreen = () => (
<SafeAreaView>
<Text>Tab One screen</Text>
</SafeAreaView>
);
const TabTwoScreen = () => (
<SafeAreaView>
<Text>Tab Two screen</Text>
</SafeAreaView>
);
const TabNavigator = () => {
return (
<Tab.Navigator tabBar={MyTabBar}>
<Tab.Screen name="TabOneScreen" component={TabOneScreen} />
<Tab.Screen name="TabTwoScreen" component={TabTwoScreen} />
</Tab.Navigator>
);
};
const Drawer = createDrawerNavigator();
const Notifications = ({ navigation }) => (
<SafeAreaView>
<Text>Notifications Screen</Text>
<Button title="Open drawer" onPress={navigation.openDrawer} />
</SafeAreaView>
);
const Router = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={TabNavigator} />
<Drawer.Screen name="Notifications" component={Notifications} />
</Drawer.Navigator>
);
};
export default Router;
Maybe the only "drawback" would be that you have to customize the custom tab bar so that you can achieve your desired look and feel. However, that could also prove to be better in the long run, as you have more control over your tab bar and its items.

React Navigation Nested No Route Params v5

I can't seem to get any route params in my nested navigator. The params are present in the parent navigator, but they are not reachable in the child navigator.
So the child navigator does render the correct screen, but it does not have any params in the route (namely a category or product id).
It feels like I am misusing some syntax, but I can't quite figure out which one. Here is the stack of code, edited down a bit to make it easier to read.
Snack on Expo
Thank you.
Note: These are separate files so the includes are off.
import * as React from 'react';
import { Text, View, StyleSheet, SafeAreaView } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { NavigationContainer } from '#react-navigation/native'
import { createDrawerNavigator, DrawerContentScrollView, DrawerItem } from '#react-navigation/drawer'
import { createStackNavigator } from '#react-navigation/stack'
import { AppearanceProvider } from 'react-native-appearance'
const Drawer = createDrawerNavigator()
const Stack = createStackNavigator()
const HomeScreen = ({ navigation, route }) => {
return(
<View style={styles.container}>
<Text>Home Screen </Text>
</View>
)
}
const CategoryScreen = ({ navigation, route }) => {
return(
<View>
<Text>Category Screen </Text>
<Text>{JSON.stringify(route)}</Text>
</View>
)
}
const ProductScreen = ({ navigation, route }) => {
return(
<View>
<Text>Product Screen </Text>
<Text>{JSON.stringify(route)}</Text>
</View>
)
}
const CustomDrawerContent = ({ props }) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
label="Home"
onPress={() => props.navigation.navigate('Home')}
/>
<DrawerItem
label="Category 1"
onPress={() =>
props.navigation.navigate('Main', {
Screen: 'Category',
params: { id: 1 },
})
}
/>
<DrawerItem
label="Category 2"
onPress={() =>
props.navigation.navigate('Main', {
Screen: 'Category',
params: { id: 101 },
})
}
/>
</DrawerContentScrollView>
)
}
const MainNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Category" component={CategoryScreen} />
<Stack.Screen name="Product" component={ProductScreen} />
</Stack.Navigator>
)
}
const ApplicationNavigator = () => {
return (
<NavigationContainer initialRouteName="Home">
<Drawer.Navigator
drawerContent={(props) => {
return <CustomDrawerContent props={props} />
}}
>
<Drawer.Screen
name="Home"
component={HomeScreen}
/>
<Drawer.Screen
name="Main"
component={MainNavigator}
/>
</Drawer.Navigator>
</NavigationContainer>
)
}
export default function App() {
return <ApplicationNavigator />
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
padding: 8,
backgroundColor: '#FFFFFF',
},
});
UPDATE
I have noted that if I initialize the params (blank, with values, whichever) outside of the custom drawer content first, the above code begins to work as expected.
Very simple and silly fix that a rubber duck could solve.
Screen !== screen. I was passing in an unknown param to navigate.

React Native: How to use deep linking with iOS?

I'm trying to use deep linking in my react native app for ios. I've been following this document by React Navigation.
I added what was needed to my AppDelegate.m and to Xcode:
However I'm confused on how to implement this in my App.js:
const AuthStack = createStackNavigator();
const AuthStackScreen = () => (
<AuthStack.Navigator >
<AuthStack.Screen
name="Ingresar"
component={Login}
options = {{
headerShown: false,
title: "Bienvenido"
}}/>
<AuthStack.Screen name="CrearCuenta"
component={Signup}
options={{title: "Crear cuenta"}}/>
</AuthStack.Navigator>
);
const Tabs = createBottomTabNavigator();
const HomeStack = createStackNavigator();
const DonationsStack = createStackNavigator();
const DonateStack = createStackNavigator();
const InstitutionsStack = createStackNavigator();
const ProfileStack = createStackNavigator();
const DonationsStackScreen = () => (
<DonationsStack.Navigator>
<DonationsStack.Screen name="Pedidos" component={DonationsScreen}/>
<DonationsStack.Screen name="Realizar donación" component={DonationFormScreen}/>
<DonationsStack.Screen name="Donación confirmada" component={DonationConfirmationScreen}
options = {{
headerShown: false
}}/>
</DonationsStack.Navigator>
);
// I omit some of the stack screens here.
const TabsScreen = () => (
<Tabs.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) =>
{
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
return <MaterialCommunityIcons name={iconName} size={size} color={color}/>;
} else if (route.name === 'Pedidos') {
iconName = focused ? 'ios-list-box' : 'ios-list';
}
else if (route.name === 'Donar') {
iconName = focused ? 'gift' : 'gift-outline';
return <MaterialCommunityIcons name={iconName} size={size} color={color}/>;
} else if (route.name === 'Perfil') {
iconName = focused ? 'user-alt'
: 'user';
return <FontAwesome5 name={iconName} size={size-4} color={color}/>;
} else if (route.name === 'Instituciones') {
iconName = 'md-business';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: '#013773',
inactiveTintColor: 'gray',
}}>
<Tabs.Screen name="Home" component={HomeStackScreen}/>
<Tabs.Screen name="Pedidos" component={DonationsStackScreen}/>
<Tabs.Screen name="Donar" component={DonateStackScreen}/>
<Tabs.Screen name="Instituciones" component={InstitutionsStackScreen}/>
<Tabs.Screen name="Perfil" component={ProfileStackScreen}/>
</Tabs.Navigator>
);
const RootStack = createStackNavigator();
const RootStackScreen = ({user}) => (
<RootStack.Navigator headerMode="none">
{user ? (
<RootStack.Screen
name="App"
component={TabsScreen}
options={{animationEnabled: false}}/>
) : (
<RootStack.Screen
name="Auth"
component={AuthStackScreen}
options={{animationEnabled: false}}/>
)}
</RootStack.Navigator>
);
export default function ponte() {
const [isLoading, setIsLoading] = React.useState(false);
const [user, setUser] = React.useState(null);
// Handle user state changes
function onAuthStateChanged(user) {
setUser(user);
if (isLoading) setIsLoading(false);
}
if (isLoading) return null;
useEffect(() => {
SplashScreen.hide();
const subscriber = auth().onAuthStateChanged(onAuthStateChanged);
return subscriber; // unsubscribe on unmount
}, []);
const authContext = React.useMemo(() => {
return {
signIn: (email, password) =>
auth()
.signInWithEmailAndPassword(email.email, password.password)
.then(res => {
setIsLoading(false);
setUser(res.user.uid);
})
,
signUp: () => {
setIsLoading(false);
setUser("test");
},
signOut: () => {
setIsLoading(false);
auth().signOut().then(() => console.log('User signed out!'));
setUser(null);
}
};
}, []);
/*
Here comes my deeplinking.
What I need to do is that when the user clicks on my URL
it goes to Pedidos --> Realizar donación with a parameter called request.
All of this happens inside the DonationsStack
*/
const deepLinking = {
prefixes: ['https://demoApp.com', 'demoApp://'],
config: {
Home: 'HomePath',
RealizarDonacion: {
path: 'Pedidos/Realizar donación/:request',
params: {
request: null,
}
}
} ,
};
return(
<AuthContext.Provider value={authContext}>
<NavigationContainer linking={deepLinking}>
<RootStackScreen user={user} />
</NavigationContainer>
</AuthContext.Provider>
);
}
As you see at the end I provide my deepLinking component to the NavigationContainer.
However when I type demoApp://Pedidos/Realizar donación/44 in Safari I don't get redirected to my app.
I'm not convinced about that space inside the path, however it doesn't work when I create a deepLink to Pedidos only either.
I need my URL to open my app and inside the DonationsStack navigate to Pedidos (DonationsScreen) --> Realizar donación (DonationFormScreen)
Update: My app opens but I don't get redirected to any screen.

react Navigation 3.x open drawer from header button?

I want to create a header on top with title for each screen and button on the right to open the drawer in react navigation 3.x
In the code below the header does not show.
//Updated with Current code
import React, { Component } from 'react';
import { Button } from 'react-native';
import {
createStackNavigator,
createDrawerNavigator,
createAppContainer
} from 'react-navigation';
import MyHomeScreen from './components/HomeScreen';
import MyNotificationsScreen from './components/ProfileScreen';
const MyDrawerNavigator = createDrawerNavigator(
{
Home: {
screen: MyHomeScreen
},
Notifications: {
screen: MyNotificationsScreen
}
},
{
initialRouteName: 'Home',
navigationOptions: navigationOptionsHeader
}
);
const navigationOptionsHeader = ({ navigation }) => {
return {
headerTitle: 'MY Home',
headerRight: (
<Button
onPress={() => navigation.toggleDrawer()}
title="Info"
color="#222"
/>
)
};
};
const AppContainer = createAppContainer(MyDrawerNavigator);
class App extends Component {
render() {
return <AppContainer />;
}
}
export default App;
Use this inside your screen class
static navigationOptions = ({ navigation }) => {
return {
title: 'Home',
headerLeft: (
< Icon name="menu" size={30} style={{marginStart:10}} backgroundColor="#000000" onPress={() => navigation.openDrawer()} > < /Icon>
),
};
};
try this
const MyDrawerNavigator = createDrawerNavigator(
{
Home: {
screen: MyHomeScreen
},
Notifications: {
screen: MyNotificationsScreen
}
},
{
initialRouteName: 'Home'
navigationOptions: navigationOptionsHeader,
}
);
const navigationOptionsHeader=({navigation})=>{
return {
headerRight: (
<Button
onPress={() => navigation.toggleDrawer();
}
title="Info"
color="#222"
/>
)
};
}
you can also add other stuffs in header like this
const navigationOptionsHeader=({navigation})=>{
return {
headerRight: (
<Button
onPress={() => navigation.toggleDrawer();
}
title="Info"
color="#222"
/>
)
headerLeft : <headerLeft/>,
title: //Header Title
headerStyle: { backgroundColor: '#161616', height:48, },
headerTitleStyle:{ color:'#cd9bf0', fontWeight: '400', alignSe
};
}
The navigationoptions had been renamed as defaultNavigationOptions in v3.
Please refer the documentation from https://reactnavigation.org/docs/en/headers.html
For React Navigation 5
Use the prop options as a function:
<Stack.Screen
name="screen name"
component={ScreenComponent}
options={({ navigation }) => ({
headerRight: (props) => {
return <Button onPress={() => navigation.toggleDrawer() }} />
}
})}
/>
https://reactnavigation.org/docs/upgrading-from-4.x/#configuring-the-navigator
For react navigation 5.x
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerLeft: () => (
<View>
<Icon
onPress={() => navigation.toggleDrawer()}
name="menu"
/>
</View>
),
}}
/>