'DrawerOpen' working but invisible contents in react-native - react-native

Using react-native
"react": "16.0.0",
"react-native": "0.50.4",
and Using 'react-navigation 1.0'
everything works well but when i press drawer menu to open it's working to open but its invisible only shows underlay color (black)
i tried to remove header component on the other stack navigator..or look for problem inside DrawerComponent. but still can not figure out.
it worked fine when i didn't change to Tab Navigation though, i needed to add Tab Navigator so changed it.
please help me
const RootNavigator = StackNavigator({
Init : { screen : InitComponent },
Root : { screen : TabStack },
})
const TabStack = TabNavigator({
DrawerStack: { screen : DrawerStack, },
AddrDrawerStack : {screen : AddrDrawerStack},
StorageDrawerStack : {screen : StorageDrawerStack},
},
{
navigationOptions:({navigation})=>({
header:<HeaderContainer navigation={navigation} />,
tabBarIcon : ({focused, tintColor}) =>{
const { routeName } = navigation.state;
return <FontAwesome size={25} color={tintColor}>{icon}</FontAwesome>;
},
}),
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
//animationEnabled: false,
swipeEnabled: true,
})
const DrawerStack = DrawerNavigator({
MailStack : {screen: MailStack},
}, {
gesturesEnabled: false,
contentComponent: DrawerContainer,
})
** DrawerContainer.js **
class DrawerContainer extends React.Component {
constructor(props, context){
super(props,context);
this.state = {
selectMenu: false,
}
this.props.getMailboxMenuList();
this.menuClick = this.menuClick.bind(this);
}
menuClick(menuName){
this.setState({
selectMenu: true,
});
this.props.mailBoxChange(menuName)
this.props.navigation.navigate("DrawerStack", {menu:menuName});
}
render() {
const { navigation, mailboxMenuList } = this.props;
if(!mailboxMenuList){
return (
<View style={styles.container}>
<Text>try again</Text>
</View>
)
}
return (
<View style={styles.container}>
<View style={styles.menuMailTop}>
<TouchableHighlight
onPress={()=>{this.props.navigation.navigate("PostScreen",{type:'write'})}}
style={styles.menuMailBoxBtn} >
<Text> write </Text>
</TouchableHighlight>
</View>
<View>
{
mailboxMenuList.items? <BasicMailBox
mailList={mailboxMenuList.items}
onReloadClick={this.props.reloadExternalMailbox.bind(this)}
externalLoading={this.props.externalLoading}
selectMenu ={this.state.selectMenu}
menuClick={this.menuClick.bind(this)} />
:<View></View>
}
</View>
</View>
) }
}
** Drawer open method**
<TouchableHighlight
onPress= {() => {
//when i press this, index indicates 0
if (navigation.state.index === 0) {
navigation.navigate('DrawerOpen')
// navigation.openDrawer()
} else {
navigation.navigate('DrawerClose')
}
}
} >
</TouchableHighlight>

Related

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 Navigation: A drawer with a stack and you want to hide the drawer on certain screens, but it doesn't hide

I'm facing the situation described in the docs, where I have a drawer with a stack and I want to hide the drawer on certain screens. Unfortunately the code below, influenced by the docs, does not work and the drawer can still be opened on pushed stack screens.
const MenuStack = createStackNavigator(
{
CheckedInMenu: { screen: MenuScreen },
CheckedIdMenuItemDetail: { screen: MenuItemDetailScreen }
},
{
navigationOptions: ({ navigation }) => {
let options = {
headerTitleStyle: {
color: headerColor
},
headerBackTitleStyle: {
color: headerColor
},
headerTintColor: headerColor
};
let drawerLockMode = "unlocked";
if (navigation.state.index > 0) {
drawerLockMode = "locked-closed";
}
return { ...options, drawerLockMode };
}
}
);
const checkedInDrawer = createDrawerNavigator(
{
MenuStack: {
screen: MenuStack,
navigationOptions: {
drawerLabel: SCREEN_TEXT_MENU_HEADER,
drawerIcon: ({ tintColor }) => (
<Image
source={require("../assets/icons/menu.png")}
resizeMode="contain"
style={{ width: 25, height: 25, tintColor: tintColor }}
/>
)
}
}
},
{
initialRouteName: "MenuStack",
drawerBackgroundColor: backgroundColor,
contentComponent: BurgerMenu,
contentOptions: {
activeTintColor: activeTintColor,
inactiveTintColor: headerColor,
activeBackgroundColor: backgroundColor,
itemStyle: { borderBottomWidth: 1, borderColor: borderColor },
labelStyle: { fontSize: 16, fontWeight: "500" }
}
}
);
What am I doing wrong?
Edit
Even if I console.log() the everything like this:
let options = {
headerTitleStyle: {
color: headerColor
},
headerBackTitleStyle: {
color: headerColor
},
headerTintColor: headerColor
};
let drawerLockMode = "unlocked";
console.log(navigation);
if (navigation.state.routeName !== "CheckedInMenu") {
drawerLockMode = "locked-closed";
}
if (navigation.state) console.log(navigation.state.routeName);
console.log({ ...options, drawerLockMode: drawerLockMode });
return { ...options, drawerLockMode: drawerLockMode };
It says on the CheckedInMenuItemDetailScreen that drawerLockMode = "locked-closed".
EDIT 2:
I now found out that the ONLY way to achieve this is exactly the way the docs say. You must do it like this:
MainStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = "unlocked";
if (navigation.state.index > 0) {
drawerLockMode = "locked-closed";
}
return {
drawerLockMode
};
};
And you must try to do it within the navigationOptions of the definition of the stack, like I did in my original post above. Keep that in mind!
This code works. When navigate to DetailsScreen, the DrawerMenu is hidden. I have implemented it using your referenced the offical docs here.
import React, { Component } from 'react';
import { Platform, StyleSheet, TouchableHighlight, Text, View } from 'react-native';
import { createStackNavigator, createDrawerNavigator, createSwitchNavigator } from 'react-navigation';
class ProfileScreen extends Component {
render() {
return (
<View>
<Text> ProfileScreen </Text>
</View>
)
}
}
class DetailsScreen extends Component {
render() {
return (
<View>
<Text> DetailsScreen </Text>
</View>
)
}
}
class HomeScreen extends Component {
render() {
const { navigate } = this.props.navigation
return (
<View>
<Text> HomeScreen </Text>
<TouchableHighlight
onPress={() => navigate("Details", { screen: "DetailsScreen" })}
>
<Text>Screen One </Text>
</TouchableHighlight>
</View>
)
}
}
const FeedStack = createStackNavigator({
FeedHome: {
screen: HomeScreen,
navigationOptions: {
title: "test"
}
},
Details: DetailsScreen,
});
FeedStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
if (navigation.state.index > 0) {
drawerLockMode = 'locked-closed';
}
return {
drawerLockMode,
};
};
const DrawerNavigator = createDrawerNavigator({
Home: FeedStack,
Profile: ProfileScreen,
});
const AppNavigator = createSwitchNavigator(
{
Drawer: DrawerNavigator,
}
);
export default class App extends Component {
render() {
return (
<View style={{ flex: 1 }} >
<AppNavigator />
</View>
);
}
}

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 activeBackgroundColor/activeTintColor for custom sidebar

I'm calling custom sidebar inside DrawerNavigator. I'm trying to set active tint color and active background color for selected menu.
const DrawerStack = DrawerNavigator(
{
ProfileScreen: { screen: ProfileScreen },
Home: { screen: DashboardScreen },
},
{
contentOptions: {
activeTintColor: "#e91e63",
activeBackgroundColor : 'purple',
},
gesturesEnabled: false,
swipeEnabled: false,
contentComponent: SideDrawer
});
1) Pass props to SideDrawer.
2) Use props.navigation.state.routes[props.navigation.state.index].routeName
to detect the current route in SideDrawer and apply styles accordingly.
I am sure you can change the background color in the custom contentComponent. In the SideDrawer jsx have a parent View with a background color.
You should pass props to your component. And extract 'activeTintColor' and 'activeBackgroundColor' from props.
const DrawerStack = DrawerNavigator(
{
ProfileScreen: { screen: ProfileScreen },
Home: { screen: DashboardScreen },
},
{
contentOptions: {
activeTintColor: "#e91e63",
activeBackgroundColor : 'purple',
},
gesturesEnabled: false,
swipeEnabled: false,
contentComponent: props => <SideDrawer {...props}/>
});
In SideDrawer
const SideDrawer = props => {
let { activeTintColor, activeBackgroundColor } = props;
return ( //your implementation
<View
style={{
backgroundColor: activeBackgroundColor
}}
>
<Text style={{ color: activeTintColor }}>Title</Text>
</View>
);
};
This is my solution to having to render a background color dynamically. its not the best because of code repetition but it works
<SafeAreaView>
<View style={styles.itemContainer}>
<TouchableOpacity
style={[styles.item, props.navigation.state.routes[props.navigation.state.index].routeName === 'Inbox'
? { backgroundColor: Colors.PRIMARY_GREEN }
: null ]}
onPress={() => {props.navigation.navigate('Inbox')}}
>
<Image
source={require('../assets/img/white-inbox.png')}
style={styles.icon}
resizeMode={'contain'}
/>
<Components.BodyText text={'Inbox'} style={styles.itemText} />
</TouchableOpacity>
</View>
</SafeAreaView>

How To Reload View Tap on TabNavigator in React Native

I want to reload the tabNavigator when the user changse the tab each time. the lifecycle method of react native doesn't get called when user changes the tab. Then how can it be possible to reload tab in TabNavigator :
The below example have two Tabs : 1) Home 2)Events. Now I want to refresh the event Tab when user returns from the home tab.
EXPO LINK : Expo Tab Navigator
Code :
import React, {Component} from 'react';
import {View, StyleSheet, Image, FlatList, ScrollView, Dimensions } from 'react-native';
import { Button, List, ListItem, Card } from 'react-native-elements' // 0.15.0
//import { Constants } from 'expo';
import { TabNavigator, StackNavigator } from 'react-navigation'; // 1.0.0-beta.11
//image screen width and height defs
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
export default class App extends Component {
render() {
//const { navigate } = this.props.navigation;
return (
<TabsNav />
)
}
}
class MyHomeScreen extends Component {
render() {
return (
<View>
<Image
resizeMode="cover"
style={{ width: windowWidth * .85, height: windowHeight * 0.3}}
source={{uri: 'http://www.ajaxlibrary.ca/sites/default/files/media/logo.png?s358127d1501607090'}}
/>
<Button
onPress={() => this.props.navigation.navigate('Notifications')}
title="Go to notifications"
/>
</View>
);
}
}
class AplEvents extends Component {
static navigationOptions = {
tabBarLabel: 'Events List',
tabBarIcon: ({ tintColor }) => (
<Image
source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
};
constructor(props) {
super(props);
this.state = {
data: [],
error: null,
};
}
// when component mounts run the function fetch
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const url = `http://www.ajaxlibrary.ca/?q=calendar-test`;
fetch(url)
.then((res) => res.json())
.then((res) => {
this.setState({
data: [...this.state.data, ...res.nodes],
error: res.error || null,
});
})
.catch(error => {
this.setState( error );
});
};
render() {
const { navigate } = this.props.navigation;
return (
<List containerStyle={{ marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<ListItem
//squareAvatar
title={`${item.node.title}\n${item.node.Program_Location}`}
subtitle={item.node.Next_Session}
avatar={{ uri: item.node.Image }}
containerStyle={{ borderBottomWidth: 0 }}
// save params to pass to detailed events screen
onPress={() => navigate('Details', {title: `${item.node.title}`,
body: `${item.node.Body}`,
date: `${item.node.Date}`,
Next_Session: `${item.node.Next_Session}`,
Program_Location: `${item.node.Program_Location}`,
Nid: `${item.node.Nid}`,
Image: `${item.node.Image}`,
Run_Time: `${item.node.Run_Time}`})}
/>
)}
keyExtractor={item => item.node.Nid}
/>
</List>
);
}
}
class EventDetails extends Component {
static navigationOptions = {
title: 'EventDetails'
};
render() {
const { params } = this.props.navigation.state;
let pic = {
uri: `${params.Image}`
};
//const pic = { params.Image };
return (
<ScrollView>
<Card
title={params.title}
>
<Image
resizeMode="cover"
style={{ width: windowWidth * .85, height: windowHeight * 0.3}}
source={pic}
/>
<Button style={{marginTop: 10}}
icon={{name: 'date-range'}}
backgroundColor='#03A9F4'
fontFamily='Lato'
buttonStyle={{borderRadius: 0, marginLeft: 0, marginRight: 0, marginBottom: 0}}
title='Add to Calendar'
/>
<ListItem
title="Event Description"
subtitle={params.body}
hideChevron='true'
/>
<ListItem
title="Date"
subtitle={`${params.Next_Session}\n Run Time - ${params.Run_Time}`}
hideChevron='true'
/>
<ListItem
title="Location"
subtitle={params.Program_Location}
hideChevron='true'
/>
</Card>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
icon: {
width: 26,
height: 26,
},
});
const EventStack = StackNavigator({
EventList: {
screen: AplEvents,
navigationOptions: {
title: "APL Event Listing",
}
},
Details: {
screen: EventDetails,
},
TabsNav: { screen: MyHomeScreen}
});
const TabsNav = TabNavigator({
Home: {
screen: MyHomeScreen,
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor }) => (
<Image
source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
},
},
EventList: {
screen: EventStack,
navigationOptions: {
tabBarLabel: 'Events',
tabBarIcon: ({ tintColor }) => (
<Image
source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
},
},
}, {
tabBarOptions: {
activeTintColor: '#e91e63',
},
});
React Native Tab Navigation has an option prop as unmountOnBlur set it to true and it will reload the tab screens every time you click on tabs.
<Tab.Screen name={"Profile"} component={ProfileScreen} options={{unmountOnBlur: true}} />
Doc/Ref - RN Bottom tab Navigator docs
.
Update - There is a hook called as useIsFocused in '#react-navigation/native'.
Use this with useEffect to re-render the screen every time it is focused or used .
import { useIsFocused } from '#react-navigation/native';
const isFocused = useIsFocused();
useEffect(() => { yourApiCall(); }, [isFocused])
look at this link. My problem is solving thanks to this.
<Tabs.Navigator
initialRouteName="Home"
tabBar={(props) => (
<TabBar {...props} />
)}>
<Tabs.Screen
name="Home"
component={HomeView}
options={{ unmountOnBlur: true }}
listeners={({ navigation }) => ({
blur: () => navigation.setParams({ screen: undefined }),
})}
/>
</Tabs.Navigator>
https://github.com/react-navigation/react-navigation/issues/6915#issuecomment-692761324
There's many long discussion about this from react-native issue 314, 486, 1335, and finally we got a way to handle this, after Sep 27, 2017, react-navigation version v1.0.0-beta.13:
New Features
Accept a tabBarOnPress param (#1335) - #cooperka
So here we go,
Usage:
const MyTabs = TabNavigator({
...
}, {
tabBarComponent: TabBarBottom /* or TabBarTop */,
tabBarPosition: 'bottom' /* or 'top' */,
navigationOptions: ({ navigation }) => ({
tabBarOnPress: (scene, jumpToIndex) => {
console.log('onPress:', scene.route);
jumpToIndex(scene.index);
},
}),
});
I wasn't able to get this to work, and after checking the React Navigation documentation, found this, which seems to suggest that later versions (I'm using 1.0.0-beta.27) changed the method signature to a single object:
tabBarOnPress Callback to handle tap events; the argument is an object
containing:
the previousScene: { route, index } which is the scene we are leaving
the scene: { route, index } that was tapped
the jumpToIndex method
that can perform the navigation for you
https://reactnavigation.org/docs/en/tab-navigator.html#tabbaronpress
Given that, and the code from beausmith here, I put this together.
navigationOptions: ({ navigation }) => ({
tabBarOnPress: (args) => {
if (args.scene.focused) { // if tab currently focused tab
if (args.scene.route.index !== 0) { // if not on first screen of the StackNavigator in focused tab.
navigation.dispatch(NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: args.scene.route.routes[0].routeName }) // go to first screen of the StackNavigator
]
}))
}
} else {
args.jumpToIndex(args.scene.index) // go to another tab (the default behavior)
}
}
})
Note that you'll need to import NavigationActions from react-navigation for this to work.
Hope this helps somebody :)