Toggling a drawer from header icon using react-navigation - react-native

I am new to react-native and react-navigation.
Required Screen: A home page with a header (Thumbnail + title) , two tabs and a drawer that toggles onPress of the thumbnail.
Please check my code:
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {Icon, Button} from 'native-base';
const util = require('util');
import { TabNavigator, StackNavigator, DrawerNavigator, NavigationActions } from 'react-navigation';
import FirstScreen from './tabs/FirstScreen';
import SecondScreen from './tabs/SecondScreen';
import Profile from './Profile';
import SearchScreen from './tabs/SearchScreen';
const DrawerScreens = DrawerNavigator({
Profile: {screen: Profile}
},{
drawerPosition: 'left',
drawerWidth: 150
});
// A drawer navigator
const TabScreens= TabNavigator({
First: {screen: FirstScreen},
Second: {screen: SecondScreen}
});
// Started with a tab navigator to register two tabs
const MenuButton =({navigation})=>{
return(
<View>
<TouchableOpacity onPress={()=>(navigation.navigate('DrawerToggle'))}>
<Icon name="person" size= {20}/>
</TouchableOpacity>
</View>)};
export const StackScreens= StackNavigator({
Draw: {screen: DrawerScreens},
// Drawer navigator as a screen
Display: {screen: TabScreens,
// Making the tabnavigator as a screen
navigationOptions: ({navigation})=>({
title: 'Welcome',
headerLeft: <MenuButton navigation={navigation} />
})
},
},{
initialRouteName: 'Display'
});
On pressing of the thumbnail the TabScreens navigates to the DrawerScreens (since that is how i coded). I want to make it toggle. Can someone please help me.

Here's some general ideas on how to structure your navigator properly.
What react-navigation version are you using?
Try changing your MenuButton helper method to this and see if it helps
if (navigation.state.index === 0) {
navigation.navigate('DrawerOpen')
} else {
navigation.navigate('DrawerClose')
}

Related

Drawer navigator in react-native using react-navigation 4.x

I want to create a drawer navigator using react navigation 4.x in react native, but not getting drawer menu in left side of the screen. Here is my code for the navigation component.
It includes three screens First,Home and Login that i want to show in drawer menu.
import {
createSwitchNavigator,
createAppContainer,
//createDrawerNavigator,
// createBottomTabNavigator,
} from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createDrawerNavigator } from 'react-navigation-drawer';
import FirstScreen from '../screen/FirstScreen';
import HomeScreen from '../screen/HomeScreen';
import LoginScreen from '../screen/LoginScreen';
const AppStack = createStackNavigator ({
First: {screen: FirstScreen},
// Dashboard: {screen: AppDrawerNavigator},
Login: {screen: LoginScreen},
Home: {screen: HomeScreen},
})
const AppDrawerNavigator = createDrawerNavigator({
Dashboard: {screen:AppStack}
});
const switchNavigator = createSwitchNavigator({
First: {screen: FirstScreen},
Dashboard: {screen: AppDrawerNavigator},
Login: {screen: LoginScreen},
Home: {screen: HomeScreen},
});
const AppNavigator = createAppContainer(switchNavigator);
export default AppNavigator;
If you want to keep your AppStack as stackNavigator then you have to create custom drawer navigator and need to pass it on createDrawerNavigator.
So first create CustomDrawer.js as below :
import React, { Component } from 'react';
import { View, Text, ScrollView, TouchableOpacity } from 'react-native';
import { NavigationActions } from 'react-navigation';
class CustomDrawer extends Component {
constructor(props) {
super(props);
this.state = {
menus: [
key: 'First', title: 'First', screen: 'FirstScreen',
key: 'Login', title: 'Login', screen: 'LoginScreen',
key: 'Home', title: 'Home', screen: 'HomeScreen'
]
};
}
navigateToScreen = (route) => {
const navigateAction = NavigationActions.navigate({
routeName: route
});
this.props.navigation.dispatch(navigateAction);
this.props.navigation.closeDrawer();
}
render() {
return (
<ScrollView style={{flex: 1}}>
{
this.state.menus.map((menu) => (
<TouchableOpacity key={menu.key} onPress={() => this.navigateToScreen(menu.screen)}>
<Text>{menu.title}</Text>
</TouchableOpacity>
))
}
</ScrollView>
);
}
}
export default CustomDrawer;
Then on in your AppNavigator.js pass CustomDrawer as contentComponent in createDrawerNavigator as below :
const DrawerNavigator = createDrawerNavigator({
Dashboard: {
screen: AppStack,
}
}, {
contentComponent: CustomDrawer, // Pass here
// others props
drawerBackgroundColor: 'rgba(255,255,255,.9)',
overlayColor: 'rgba(0,0,0,0.5)',
contentOptions: {
activeTintColor: '#fff',
activeBackgroundColor: '#6b52ae',
},
});
If you want more style you can done in CustomDrawer.js.
you are returning the switch navigator, try this way , embed switch-navigator object with drawer-navigator object and return drawer-navigator object. refer below,
const AppDrawerNavigator = createDrawerNavigator({
First: {screen: FirstScreen},
Login: {screen: LoginScreen},
Home: {screen: HomeScreen},
switchNavigator: switchNavigator
});
const AppNavigator = createAppContainer(AppDrawerNavigator);
export default AppNavigator;

Icon not rendering from Ionicon vector icons in header

Trying to render a menu icon in the upper left corner for a stack navigator nested inside a bottom tab navigator. I am using react-navigation-header-buttons library for aid in formatting the icon in the stack header. Basically, the title of the Item component "Menu" is showing rather than the icon I am attempting to use.
//HomeScreenNavigator.js
import React from 'react';
import { createStackNavigator } from 'react-navigation-stack';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import HomeScreen from '../screens/HomeScreen';
import MediaSelectScreen from '../screens/MediaSelectScreen';
import FinalizePostScreen from '../screens/FinalizePostScreen';
import Colors from '../constants/Colors';
import CustomHeaderButton from '../components/HeaderButton';
const HomeScreenNavigator = createStackNavigator({
Home: { screen: HomeScreen, navigationOptions: {
headerTitle: 'Feed',
headerLeft: (
<HeaderButtons> HeaderButtonComponent={CustomHeaderButton}
<Item title="Menu" iconName="ios-menu" onPress={() => {}} />
</HeaderButtons>
)
}},
MediaSelect: MediaSelectScreen,
FinalizePost: FinalizePostScreen
}, {
defaultNavigationOptions: {
headerStyle: {
backgroundColor: Colors.accentColor
}
}
});
export default HomeScreenNavigator;
//HeaderButton.js
import React from 'react';
import { HeaderButton } from 'react-navigation-header-buttons';
import { Ionicons } from '#expo/vector-icons';
import Colors from '../constants/Colors';
const CustomHeaderButton = props => {
return <HeaderButton
{...props}
IconComponent={Ionicons}
iconSize={23}
color={Colors.iconSelectedOutline}
/>
};
export default CustomHeaderButton
No error messages are shown but no icon is shown either. Instead The header bar just has a headerLeft button with text "MENU" and then the Header title "Feed". screenshot-simulator
Line of code that was causing the issue:
<HeaderButtons> HeaderButtonComponent={CustomHeaderButton}
Needs to be:
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>

undefined is not an object (evaluating '_this.props.navigation.navigate') upon button click

I am fairly new to react-native and react-navigation and trying to move from one screen to another via button click, keep getting this error. I've found similar questions here on SO (this and this) but they don't work for me, keep getting this error.
What I am doing is, I have an App.js that is the initial screen which for now shows a login form (called Splash):
import React from 'react';
import {
View,
ActivityIndicator,
StyleSheet
} from 'react-native';
import { createDrawerNavigator, createAppContainer } from "react-navigation";
import HomeScreen from './HomeScreen';
import ProfileScreen from './ProfileScreen';
import Splash from './Splash';
export default class App extends React.Component {
render() {
const { navigation } = this.props;
return (
<View>
<Splash navigation={navigation}/>
</View>
);
}
}
const AppNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen
},
Profile: {
screen: ProfileScreen
}
}, {
initialRouteName: "Home",
contentOptions: {
activeTintColor: '#e91e63'
}
});
const AppContainer = createAppContainer(AppNavigator);
On my Splash screen I now have no functionality as I am just trying to get it to move to my HomeScreen when I hit the Login button:
import React, { Component } from 'react';
import {
ScrollView,
Text,
TextInput,
TouchableOpacity,
StyleSheet
} from 'react-native';
class Splash extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ScrollView style={{padding: 20}}>
<TextInput autoCapitalize="none"
onSubmitEditing={() => this.passwordInput.focus()}
autoCorrect={false}
keyboardType='email-address'
returnKeyType="next"
placeholder='Email address'
placeholderTextColor='rgba(225,225,225,0.7)'/>
<TextInput returnKeyType="go"
ref={(input)=> this.passwordInput = input}
placeholder='Password'
placeholderTextColor='rgba(225,225,225,0.7)'
secureTextEntry/>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Home')}>
<Text>LOGIN</Text>
</TouchableOpacity>
</ScrollView>
)
}
};
export default Splash;
What happens now is that as soon as I hit the login button, I get the error in the title. Any clues on what I am doing wrong?
Remove App component, you don't need it in this case. Make Splash as your initial screen
const AppNavigator = createDrawerNavigator({
Splash: {
screen: Splash
},
Home: {
screen: HomeScreen
},
Profile: {
screen: ProfileScreen
}
}, {
initialRouteName: "Splash",
contentOptions: {
activeTintColor: '#e91e63'
}
});
then export AppContainer directly
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer

Single screen application without bottom navigation bar

I've analyzed the needs of my application and decided I can more efficiently develop it with mobile friendly components on the web and present it via a web view in an app.
I need permissions to access camera and gallery (to take photos / videos, and upload photos / videos).
Basically, a single-screen app with a webview presenting the site with mobile-friendly components and the above permissions.
This is my current app.js:
import React from 'react';
import { Button, Text, View, TouchableOpacity, StyleSheet } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {
createStackNavigator,
createBottomTabNavigator,
createAppContainer,
} from 'react-navigation';
//import createStackNavigator, createBottomTabNavigator, createAppContainer in our project
import HomeScreen from './pages/HomeScreen';
import { Constants, Location, Camera, Permissions } from 'expo';
const ProfileStack = createStackNavigator(
{
//Definition of Navigaton from home screen
HomeScreen: { screen: HomeScreen },
},
{
//For React Navigation 2.+ change defaultNavigationOptions->navigationOptions
defaultNavigationOptions: {
//Header customization of the perticular Screen
headerStyle: {
backgroundColor: 'orange',
},
headerTintColor: '#FFFFFF',
title: '',
//Header title
},
}
);
const App = createBottomTabNavigator(
{
HomeScreen: { screen: HomeScreen },
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons;
let iconName;
if (routeName === 'HomeScreen') {
iconName = `ios-information-circle${focused ? '' : '-outline'}`;
}
return <IconComponent name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'orange',
inactiveTintColor: 'gray',
},
}
);
export default createAppContainer(App);
and './pages/HomeScreen':
//This is an example code for Bottom Navigation//
import React, {Component} from 'react';
//import react in our code.
import { Text, View, TouchableOpacity, StyleSheet, WebView } from 'react-native';
//import all the basic component we have used
export default class ProfileScreen extends React.Component {
//Profile Screen to show from Open profile button
render() {
return (
<WebView
source={{uri: 'https://mobilesite'}}
style={{marginTop: 20}}
/>
);
}
}
So far, the site opens on a single screen as expected, but there's a bottom navigation bar present; I'd also like to preferably hide the top bar if possible too as I've accounted for that in a mobile-friendly header on the mobile site as well.
Also, via the mobile web codebase, I'm utilizing <input type="file" /> for uploading. Is this compatible with React Native Permissions?
You're using createBottomTabNavigator() and passing the resulting navigator to your createAppContainer() which will create a bottom tab navigator.
If you pass a StackNavigator (via createStackNavigator() which you use for ProfileStack) to the createAppContainer() it'll render the stack as opposed to the bottom tab navigator which is what you want.
To remove the header altogether you can use headerMode: 'none' in the navigationOptions param.
You can see a basic version of what you want here (sans the lack of a header) in the React Navigation docs.

How to add React-Navigation Drawer menu to my screens?

I have a home screen built with React-Navigation 3.x. I have a header, some navigation icons, and a bottom tab menu. It is working well, but now I want to add a drawer menu to the screen and add an icon at the top right corner to toggle the drawer.
Here's a simplified version of my home screen (App.js):
import { createStackNavigator, createAppContainer, createBottomTabNavigator } from 'react-navigation';
import Activity1 from './Activity/Activity1';
import Activity2 from './Activity/Activity2';
import Activity3 from './Activity/Activity3';
import Calendar from './Screens/Calendar';
import Graph from './Screens/Graph';
import DrawerMenu from './components/DrawerMenu';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
headerRight: (<Button onPress={() => this.props.navigation.toggleDrawer()} title='Menu' />)
};
render() {
return (
<View style={styles.container}>
<View style={styles.iconContainer}>
<Icon name='icon1' onPress={this.navToActivity1} />
<Icon name='icon2' onPress={this.navToActivity2} />
<Icon name='icon3' onPress={this.navToActivity3} />
</View>
<View>
<DrawerMenu />
</View>
</View>
);
}
}
//create my main navigation stacks here
const Home = createStackNavigator({
HomeScreen,
Activity1,
Activity2,
Activity3,
});
//The following two are for the bottom tab bar only
const Calendar = createStackNavigator({ Calendar });
const Graph = createStackNavigator({ Graph });
const BottomTabNav = createBottomTabNavigator({
Home, Calendar, Graph
});
export default createAppContainer(TabNavigator);
And here's the code for DrawerMenu.js
import { Dimensions } from 'react-native';
import { createDrawerNavigator, createAppContainer } from 'react-navigation';
import Settings from './Settings';
import Profile from './Profile';
const SCREENWIDTH = Dimensions.get('window').width;
const DrawerConfig = {
drawerWidth: SCREENWIDTH * 0.5,
drawerPosition: 'right',
};
const DrawerMenu = createDrawerNavigator({
Settings: { screen: Settings },
Profile: { screen: Profile },
},
DrawerConfig
);
export default createAppContainer(DrawerMenu);
I couldn't get the drawer to work. When I click on the "Menu" button at the top right corner in the Home Screen to invoke toggleDrawer(), I got an "undefined is not an object (evaluating 'ae.props.navigation')" error.
The drawer cannot be activated using gesture either, so I think I am not adding it correctly. What did I do wrong here? Thanks!!
install the package the react-native-drawer
https://www.npmjs.com/package/react-native-drawer
<Drawer
type="overlay"
ref={ref => (this._drawer = ref)}
content={<Sidebar />}
tapToClose={true}
openDrawerOffset={0.2} // 20% gap on the right side of drawer
panCloseMask={0.2}
closedDrawerOffset={-3}
styles={drawerStyles}
tweenHandler={ratio => ({ main: { opacity: (2 - ratio) / 2 } })}
>
cds