Open Drawer by clicking in header of containing StackNavigator - react-native

This is the component which contains my Drawer
export default class StackInView extends React.Component {
render() {
const Stack = StackNavigator({
DrawerStack: { screen: DrawerInView }
}, {
headerMode: 'float',
});
return (
<View style={{ flex: 1 }}>
<Stack />
</View>
);
}
}
The following is where I define my button. I want to define the button in navigationOptions of the screen, because the button should only appear on the screen with the drawer. But clicking the button doesn't work can you help me pls?
... imports ...
export default class DrawerInView extends React.Component {
static navigationOptions = {
title: "Yeah?",
headerRight: <Button title="Menu" onPress={() => {NavigationActions.navigate("DrawerOpen")}}/>
}
constructor(props) {
super(props);
}
render() {
const Drawer = DrawerNavigator({
"one": {
screen: () => {
return (<TabsInView select="something" />)
},
},
"two": {
screen: () => {
return (<TabsInView select="something else" />)
},
}
})
return (
<View style={{ flex: 1 }}>
<Drawer />
</View>
);
}
}

You can open DrawerNavigation on button click like this.
<Button title="Menu" onPress ={ ( ) => this.props.navigation.openDrawer()} />

Don't put Stack into View. It's hard to understand and you break all props.
And the reason it doesn't work is that navigationOptions in second code is not for the drawer but for the StackNavigator in the first code. So it can't execute drawer's navigation.navigate("DrawerOpen") because it's StackNavigator's.
And I highly recommend you to change your app's hierarchy. It's really hard that child Drawer passes its navigation to parent Stack's right button.
Then, it would look like this.
const MyStack = StackNavigator({
Tabs:{ screen: MyTabs, navigationOptions:(props) => ({
headerRight:
<TouchableOpacity onPress={() => {props.screenProps.myDrawerNavigation.navigate('DrawerOpen')}}>
<Text>Open Drawer</Text>
</TouchableOpacity>
})}
}
, {navigationOptions:commonNavigationOptions})
const MyDrawer = DrawerNavigator({
stack1: {
screen: ({navigation}) => <MyStack screenProps={{myDrawerNavigation:navigation}} />,
},
stack2: {
//more screen
}
})

Related

navigationOptions in screen component is not working

If I set the navigationOptions in the screen component inside a StackNavigator to change the header of the stack inside a DrawerNavigator the navigationOptions are not taken into account. I can however pass defaultNavigationOptions which are taken into account. If I don't pass defaultNavigationOptions it doesn't change the behavior. This is with react-navigation v 4.x
here I create the Stack navigators screens for my Drawer
drawerNavigator = () => {
let drawerRoutes = {}
this.state.routes.forEach(r => {
let stackRoute = {}
let t = () => <First name={r} />
stackRoute[r] = { screen : t }
let stackOptions = {
initialRouteName: r,
defaultNavigationOptions: stackNavigationOptions
}
let s = createStackNavigator(stackRoute, stackOptions)
drawerRoutes[r] = { screen : s }
})
let drawerOptions = {
drawerWidth: '75%',
initialRouteName: this.state.routes[0],
contentComponent: props => <Menu {...props} />,
contentOptions: drawerItemsOptions
}
return createDrawerNavigator(drawerRoutes, drawerOptions);
}
Then in my component I try to set the navigationOptions of the Stack but it is not taken into account...
export default class First extends Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: 'hahahaha',
headerRight: () => (
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="#fff"
/>
),
}
}
render() {
return (
<SafeAreaView style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<StatusBar transluscent backgroundColor="transparent" barStyle="dark-content" />
<Text>{this.props.name}</Text>
</SafeAreaView>
);
}
}
Okay I've discovered that if I pass my screen that way
stackRoute[r] = { screen : First }
instead of the
let t = () => <First name={r} />
stackRoute[r] = { screen : t }
the navigationOptions are taken into account. However I cannot pass props that way....

How to call a function in a child navigator's screen from a parent navigator's header icon

I'm using react navigation. My top level navigator is a StackNavigator. Within this StackNavigator I have a nested DrawerNavigator. I really want this implementation because I don't want the Navigation Drawer to overlap the header.
In the StackNavigator I have placed an icon (headerRight) in the header. I have a MapView as the first screen route in the nested DrawerNavigator. I want to zoom to the user's current location (which is held globally in a Context) when the icon is pressed.
I can't figure out how to do this. In order for it to work I would need a reference the MapView from the icon's onPress so I can zoom to a specific location. I don't want the DrawerNavigator to be my top-level navigator. What can I do? Here is the code for my navigators:
const DrawerNavigator = createDrawerNavigator({
"Search Locations": {
screen: (props) => (
<CurrentLocationProvider>
<BusinessLocationsProvider>
<SearchLocationsScreen {...props}/>
</BusinessLocationsProvider>
</CurrentLocationProvider>
),
},
"About": {
screen: AboutScreen,
},
"Favorites": {
screen: FavoritesScreen
},
"Profile": {
screen: ProfileScreen
},
"Issues": {
screen: ReportIssueScreen
}
}, {
contentComponent: props => <CustomDrawerComponent {...props} />,
});
const MainStackNavigator = createStackNavigator({
DrawerNavigator: {
screen: DrawerNavigator,
},
"Checkin": {
screen: CheckInScreen,
},
"Confirmation": {
screen: (props) => (
<CurrentLocationProvider>
<CheckInConfirmationScreen {...props}/>
</CurrentLocationProvider>
),
navigationOptions: {
header: null,
}
}
}, {
defaultNavigationOptions: ({navigation}) => configureNavigationOptions(navigation)
});
const LoadingNavigator = createSwitchNavigator({
"LoadingScreen": LoadingScreen,
MainStackNavigator: MainStackNavigator,
}, {
initialRouteName: "LoadingScreen",
});
export default createAppContainer(LoadingNavigator);
Here is the configuration I use for the defaultNavigationOptions in the StackNavigator:
export default (navigation) => {
const {state} = navigation;
let navOptions = {};
// navOptions.header = null;
navOptions.headerTitle = <Text style={styles.headerTitle}>Nail-Queue</Text>;
navOptions.headerStyle = {
backgroundColor: colors.primary
};
if (state.index === 0) {
navOptions.headerRight = (
<TouchableOpacity onPress={() => {
}}>
<MaterialIcons
name="my-location"
size={32}
color="#fff"
style={{paddingRight: 10}}
/>
</TouchableOpacity>
)
}
if (state.isDrawerOpen) {
navOptions.headerLeft = (
<>
<StatusBar barStyle='light-content'/>
<TouchableOpacity onPress={() => {
navigation.dispatch(DrawerActions.toggleDrawer())
}}>
<Ionicons name="ios-close" style={styles.menuClose} size={38} color={'#fff'}/>
</TouchableOpacity>
</>
)
} else {
navOptions.headerLeft = (
<>
<StatusBar barStyle='light-content'/>
<TouchableOpacity onPress={() => {
navigation.dispatch(DrawerActions.toggleDrawer())
}}>
<Ionicons name="ios-menu" style={styles.menuOpen} size={32} color={'#fff'}/>
</TouchableOpacity>
</>
)
}
return navOptions;
};
It shouldn't be this difficult to perform such a basic operation but I've been reading documentation for 2 days and getting nowhere.
Use a global variable so store map view reference value, and access that reference in you custom header component to zoom to your position.

React native set state from drawer navigator to other component

On first screen I have a component having some listing of products say ProductListing.js. And on drawer navigator I have some check boxes. I want to set state of ProductListing.js when I am clicking on any check box of navigator.
App.js
import React, {Component} from 'react';
import Router from './src/config/routes';
export default class App extends React.Component {
render () {
return (
<Router/>
);
}
}
Router.js
export default DrawerNavigator({
Dashboard: {screen: Dashboard},
CreateLogin: {screen: CreateLogin},
Test: {screen: Test}
}, {
contentComponent: SideMenu,
drawerWidth: 300,
drawerPosition: 'right'
});
SideMenu.js
render () {
const { data, searchTerm, searchAttribute, ignoreCase, checked } = this.state;
return (
<View style={styles.container}>
<ScrollView>
<View>
<TextInput
style={styles.search} placeholder={"Search"}
onChangeText={searchTerm => this.setState({ searchTerm })} />
<SearchableFlatList
data={data} searchTerm={searchTerm}
searchAttribute={searchAttribute} ignoreCase={ignoreCase}
renderItem={({ item, index }) => <CheckBox
title={item.name +' ('+ item.count+')'}
onPress={() => this.handleChange(item.id)}
checked={checked[item.id]} />
}
keyExtractor={({id}, index) => index.toString()} />
</View>
</ScrollView>
<View style={styles.footerContainer}>
<Text>Apply filter by choosing filter values</Text>
</View>
</View>
);
}
}
ProductListing.js
constructor(props){
super(props);
this.state ={ isLoading: true,isloadmore: false, page :1,dataSource: [],countryFilter:0, gradesFilter:'',country:'',totalRecord:0};
}
render(){
const { navigation } = this.props;
return(
<View style={{flexDirection:'column',paddingRight:8}}>
<Button
title='Filter'
buttonStyle={{backgroundColor:'#000000',borderRadius:2}}
onPress={() => navigation.dispatch(DrawerActions.openDrawer())}
/>
</View>
);
}
Now on click of handleChange in SideMenu.js I want to update state of gradesFilter in ProductListing.js where I am updating my product listing.
You can easily achieve this with a portal! Take a look here.
You can pass the parameters from drawer to the Product screen via navigation params.
For this, you need to stackNavigator inside your DrawerNavigator like:
Router:
const MyStack = StackNavigator({
Dashboard: {screen: Dashboard},
CreateLogin: {screen: CreateLogin},
Test: {screen: Test}
});
const MyDrawer = DrawerNavigator({
Main: { screen: MyStack }
},
{
contentComponent: SideMenu,
drawerWidth: 300,
drawerPosition: 'right'
});
export const Router = StackNavigator({
Login: {screen: Login},
Drawer: {
screen: MyDrawer,
navigationOptions: { header: null } } //prevent double header
});
Now you can navigate and pass parameter from login or Dashboard or anyother screen via Drawer like
_login() {
this.props.navigation.navigate('Drawer', { parameter: userName });
}
And to use this parameter you need to access:
const { parameter } = this.props.navigation.state.params;
which you can further use to set state like
this.setState({
productSelection: parameter)};
Another approach can be via, listener/ Callback handler.

Navigating to a new view

How to correctly navigate to a new view?
App:
TabNavigator (Top of the screen)
StackNavigator (Bottom of the screen)
I want that after choosing a button from StackNavigator opened a new screen that will override the entire application. I do not want to see TabNavigator and StackNavigator.
In the new window, I want it to be NavBar with the return button
All the tutorials that I'm watching show how to switch between screens but I can not find the situation above.
I want to open a new window from the main application and then return to it
EDITED:
const TopNavTabs = TabNavigator({
General: { screen: General },
Help: { screen: Help },
Tips: { screen: Tips },
}
});
export const Navigation = StackNavigator(
{
Tab: { screen: TopNavTabs },
Article: { screen: Article },
}
);
export default class App extends Component{
render(){
return(
<View>
<View>
<Navigation navigation={this.props.navigation} />
</View>
<View>
<View>
<MCIcon name="account"/>
</View>
<View>
<MIcon name="create" onPress={() => this.props.navigation.navigate('Article')} />
</View>
<View>
<FAIcon name="hashtag" />
</View>
<View>
<FAIcon name="search" />
</View>
</View>
</View>
)
}
}
Add TabNavigator in StackNavigator like:
const TopNavTabs = TabNavigator(
{
General: { screen: General },
Help: { screen: Help },
Tips: { screen: Tips },
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Home') {
iconName = `ios-information-circle${focused ? '' : '-outline'}`;
} else if (routeName === 'Settings') {
iconName = `ios-options${focused ? '' : '-outline'}`;
}
// You can return any component that you like here! We usually use an
// icon component from react-native-vector-icons
return <Ionicons name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
}
);
export const Navigation = StackNavigator(
{
Tab: { screen: TopNavTabs },
Article: { screen: Article },
}
);
export default class App extends Component{
render(){
return(
<Navigation />
)
}
}

React Native navigate using Touchable Opacity

I want to make the Play button to navigate to the play screen. I created a an app class as the main file. Then in my cluster1, I am able to press a play button. But I don't know how to navigate the play button to the play class screen.
This is my App Class
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<AppNavigator/>
</View>
);}}
const AppNavigator = StackNavigator({
Cluster1: {
screen: Cluster1,
},
Play: {
screen: Play,
},
});
This is my Cluster1 Class
export default class Cluster1 extends Component{
static navigationOptions = {
title: 'Choose the Mood Cluster to listen',};
render(){
return(
<View>
<SectionList
renderItem={({item,index})=>{
return(
<SectionListItem item={item} index={index}> </SectionListItem>);}}
renderSectionHeader={({ section }) => {
return (<SectionHeader section={section} />);}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}>
</SectionList>
</View>
);
}}
class SectionHeader extends Component {
render() {
const AppNavigator = StackNavigator({
Cluster1: { screen: Cluster1},
Play: { screen: Play},
});
return (
<View style={styles.header}>
<Text style={styles.headertext}>
{this.props.section.title}
</Text>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Play')}}> Play</TouchableOpacity>
</View>
);
}}
This is my Play class
export default class Play extends Component{
static navigationOptions = {
headerMode: 'none', };
render(){
return(
<View style={styles.container}>
<Text>Play Screen</Text>
</View>
);
}{
What do i add in for my touchableopacity statement?
You can use like this. Use navigation option to navigate the component
const AppNavigator = StackNavigator({
Cluster1: { screen: Cluster1},
Play: { screen: Play},
});
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Play')}}> Play</TouchableOpacity>