React native - onpress doesn't work inside drawer navigation header - react-native

I'm trying to add a custom menu icon button inside the navigation header in my react native app. I successfully did that, but the press event doesn't fire as long as the icon is in the header. For example, if I have the icon here:
https://www.dropbox.com/s/xyah9ei43wgt1ut/menu_regular.png?dl=0
The press event doesn't work, but if I have it here (moved it lower):
https://www.dropbox.com/s/54utpr1efb3o0lm/menu_moved.png?dl=0
The event fires ok.
Here's my current setup navigator:
const MainNavigator = createStackNavigator(
{
login: { screen: MainLoginScreen },
signup: { screen: SignupScreen },
profileScreen: { screen: ProfileScreen },
main: {
screen: createDrawerNavigator({
Home: createStackNavigator(
{
map: {
screen: MapScreen,
headerMode: 'screen',
navigationOptions: {
headerVisible: true,
headerTransparent: false,
headerLeft: (
<View style={{ position: 'absolute', left: 10, display: 'flex', zIndex: 11550 }}>
<Icon
raised
name='bars'
type='font-awesome'
color='rgba(255, 255, 255, 0)'
reverseColor='#444'
onPress={() => { console.log("press"); navigation.goBack() }}
reverse
/>
</View>
)
}
},
history: { screen: HistoryScreen },
foundItem: { screen: FoundItemScreen },
}
),
Settings: {
screen: SettingsScreen,
navigationOptions: ({ navigation }) => ({
title: 'Edit Profile',
})
}
}, {
contentComponent: customDrawerComponent,
drawerWidth: width * 0.8
}
)
}
}, {
headerMode: 'screen',
navigationOptions: {
headerTransparent: true,
headerLeftContainerStyle: { paddingLeft: 20 }
}
}
);
The icon from the screenshot is inside headerLeft.
I've also tried various zIndex values, but with no luck.
Thanks in advance!
Edit:
The drawer has the same issue on the first item, press events don't work on the full area of the drawer item when it's over the header:
https://www.dropbox.com/s/krva5cgp7s59d13/drawer_opened.png?dl=0

Try to wrap Icon inside some Touchable Element like TouchableOpacity/TouchableHighlight and then add an onPress prop to that element

You can get the onPress event in navigationOption's header using navigation params like
static navigationOptions = ({ navigation }) => ({
headerLeft: (
<TouchableOpacity onPress={() => navigation.state.params.handleSave()} >
<Image source={ImageSource} />
</TouchableOpacity>
)
})
Then set the navigation params from the componentDidMount like:
componentDidMount() {
this.props.navigation.setParams({ handleSave: this.onSavePress.bind(this)})
}
then can call the method like:
onSavePress() {
// Do Something
}

Related

Uber-like Drawer navigation in React Native app

I'm trying to figure out how to implement navigation in React Native app using react-navigation to make it similar to Uber app.
I'd like to use Drawer which contains a menu items like Settings, Profile etc. Click on each item should open a modal with navigation Stack with arrow left or cross icon button on the top (header) to close stack and back to main screen. When modal with navigation stack is opened I'd like to disable drawer.
Is this possible to achieve with react-navigation?
Yes react navigation drawer accepts arbitrary react components as content. You can see an example by running https://expo.io/#react-navigation/NavigationPlayground on your phone.
Some example code from https://github.com/react-navigation/react-navigation/blob/master/examples/NavigationPlayground/src/Drawer.tsx
const InboxStack = createStackNavigator(
{
Email: { screen: EmailScreen },
Inbox: { screen: InboxScreen },
},
{
navigationOptions: {
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor } as StyleProp<TextStyle>}
/>
),
drawerLabel: 'Inbox',
},
}
);
const DraftsStack = createStackNavigator(
{
Drafts: { screen: DraftsScreen },
Email: { screen: EmailScreen },
},
{
navigationOptions: {
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="drafts"
size={24}
style={{ color: tintColor } as StyleProp<TextStyle>}
/>
),
drawerLabel: 'Drafts',
},
}
);
const DrawerExample = createDrawerNavigator(
{
Drafts: {
path: '/sent',
screen: DraftsStack,
},
Inbox: {
path: '/',
screen: InboxStack,
},
},
{
contentOptions: {
activeTintColor: '#e91e63',
},
initialRouteName: 'Drafts',
}
);

component render one time when click tab on drawerNavigator in react native

I'm new on react native getting issue on calling component. Whenever click on drawer navigator tab first time component render and API called But when back to the home page and again call that component API not called. I want to recall that function.
Here is my drawer navigator code :
const AppDrawerNavigator = createDrawerNavigator({
Home: {
screen: Home,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: () => (
<Icon name="home" size={20} color="#0f1f7b" />
)
},
},
PreviousInspection: {
screen: PreviousInspection,
navigationOptions: {
drawerLabel: 'Previous Inspection',
drawerIcon: () => (
<Icon name="file" size={20} color="#0f1f7b" />
)
},
},
Logout: {
screen: Logout,
navigationOptions: {
drawerLabel: 'Logout',
drawerIcon: () => (
<Icon name="sign-out" size={20} color="#0f1f7b" />
)
},
}
},
{
drawerBackgroundColor: "#fff",
contentOptions: {
activeTintColor: '#000',
inactiveTintColor: '#000',
activeBackgroundColor: '#bfc7f3',
itemStyle: {
fontSize: 12,
},
},
});
react-navigation has a withNavigationFocus HOC which provides an isFocused prop to your component. You can use that to determine when a certain screen has become visible.
import { withNavigationFocus } from 'react-navigation';
class YourScreen extends React.Component {
render() {
...
}
componentDidUpdate(prevProps) {
if (this.props.isFocused && !prevProps.isFocused) {
// Screen has now come into focus, call your method here
}
}
}
export default withNavigationFocus(YourScreen)

CreateDrawerNavigator inside createStackNavigator

My issue is this: I can't seem to be able to add the hamburguer button on the left (to toggle the drawer) and also I cannot add the title to the drawer depending on the screen (for example, show 'Login' on header when it's on the login screen).
Brief explanation of the code:
The AppNavigation.js handles all the navigation for the app. Including the two drawers (LoggedDrawer and UnloggedDrawer).
They are inside a stack navigator (RootNavigator) and the RootNavigator is inside a container (react-navigation 3.0).
This is the code I have:
AppNavigation.js
const UnloggedDrawer = createDrawerNavigator(
{
Home: { screen: HomeScreen },
Login: { screen: LoginScreen },
SignUp: { screen: SignUpScreen }
}, {
drawerWidth: SCREEN_WIDTH * 0.6
}
)
const LoggedDrawer = createDrawerNavigator(
{
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen }
}, {
contentComponent: (props) => (
<View style={{ flex: 1 }}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {...props} />
<Button
color='red'
title='Logout'
onPress={() => { props.screenProps.logoutCurrentUser(props) }}
/>
</SafeAreaView>
</View>
),
drawerWidth: SCREEN_WIDTH * 0.6,
})
const RootNavigator = createStackNavigator({
Init: {
screen: Init,
navigationOptions: {
header: null,
},
},
UnloggedDrawer: { screen: UnloggedDrawer },
LoggedDrawer: { screen: LoggedDrawer }
},
{
mode: 'modal',
title: 'Main',
initialRouteName: 'Init',
transitionConfig: noTransitionConfig,
})
Init.js
componentWillReceiveProps(props) {
const { navigation } = props;
if (props.userReducer.isSignedUp) {
navigation.dispatch(StackActions.reset(
{ index: 0, key: null, actions: [NavigationActions.navigate({ routeName: 'LoggedDrawer' })] }
))
} else {
navigation.dispatch(StackActions.reset(
{ index: 0, key: null, actions: [NavigationActions.navigate({ routeName: 'UnloggedDrawer' })] }
))
}
}
On my screens, I have a navigationOptions for all of them just like this (the only difference is the icon), this is only part of the code just as an example:
export default class HomeScreen extends Component {
static navigationOptions = {
headerTitle: 'Home',
drawerIcon: () => (
<SimpleIcon
name="home"
color="rgba(110, 120, 170, 1)"
size={20}
/>
)};
}
So what I want to do is:
1. Add a hamburger icon to the header of all screens which will be used to toggle the drawer
2. Add the title on the middle of the header (also for all screens)
What I've tried:
Everything I could find on the internet and nothing seems to work.
Also, if my architecture is wrong, please point that out, if also there's a different way to achieve what I'm trying to do it's also accepted.
Thanks in advance. Please help.
So, answering my own question.
What I want is easily achieved by using react-native-elements.
They have a component called 'Header' that you can use on each screen to customize the header.
I added this to both of drawerNavigators and the stackNavigator.
headerMode: 'null'
Then for each screen I had to wrap the JSX code in React.Fragment, so it went like this:
<React.Fragment>
<Header
statusBarProps={{ barStyle: 'light-content' }}
barStyle="light-content"
leftComponent={
<SimpleIcon
name="menu"
color="#34495e"
size={20}
/>
}
centerComponent={{ text: 'HOME', style: { color: '#34495e' } }}
containerStyle={{
backgroundColor: 'white',
justifyContent: 'space-around',
}}
/>
</React.Fragment>
Leaving the answer in case anyone else have the same issue.

react native, show a bar above of TabNavigator, who hide on scroll ( like facebook app do)

I'm devolopping an app with react native.
I use tabNavigator and StackNavigator from react-navigation to navigate between tabs.
Now i want to create , exactly like the facebook's app, a tab displayed above my tabNavigator. This tabs hide on scroll down.
The FlatList component have ListHeaderComponent option for rendering his header who also hide when scroll down.
Any idea ?
I didn't found anything on https://reactnavigation.org/docs/ or react-native docs
Looks like a TabNavigator nested inside a StackNavigator, like below
StackNavigator(
{
Tabs: {
screen: TabNavigator(
{
TabA: {
screen: TabA,
navigationOptions: {
tabBarIcon: <MaterialCommunityIcons name={"account"} />
}
},
TabB: {
screen: TabB,
navigationOptions: {
tabBarIcon: <MaterialCommunityIcons name={"message"} />
}
},
TabC: {
screen: TabC,
navigationOptions: {
tabBarIcon: <MaterialCommunityIcons name={"earth"} />
}
}
},
{
tabBarOptions: {
showLabel: false,
showIcon: true,
style: {
backgroundColor: "white"
}
}
}
),
navigationOptions: {
title: "Notifications"
}
}
},
{
navigationOptions: ({ navigation }) => ({
headerRight: <MaterialCommunityIcons name={"magnify"} size={30} style={{ color: "white" }} />,
headerStyle: {
backgroundColor: "rgb(76, 62, 84)"
},
headerTitleStyle: { color: "white" }
})
}
)

React-Navigation Drawer and Static Tab-Navigation

i am switching from react navigator to react-navigation and i am actually fine with this approach, but struggeling with one issue.
I want to use a drawer navigation and a bottom aligned Tab-Navigation.
This part is working as expected - no issues here.
I want to have the tabbed navigation fixed with 3 Buttons that will have the same action all over the app. ( eg. dashboard / search / favourites )
From Dashboard you can navigate one level deeper. As i am doing it now, the Label of the Tab formerly "Dashboard" changes to the Name of the navigated-to Item.
to clarify, i added a stack-navigation in the Dashboard-Screen-Tab, so the user can navigate through that pages.
How can i prevent the tabs' labes and actions to change while navigating within the tabs' stack?
Basically i want a fixed Tab Navigation on each screen.
Should i create a fixed View-Component to achieve that?
Here is my setup:
App.js
const MetaTabNavigator = TabNavigator({
Dashboard: {
screen: MachineNavigator
},
Search: { screen: SearchScreen },
Favourites: { screen: FavouritesScreen },
},
{
tabBarPosition: Platform.OS === "ios" ? 'bottom' : 'top',
animationEnabled: true,
tabBarOptions: {
activeTintColor: STYLES.HIGHLIGHT_COLOR
},
swipeEnabled: false,
backBehavior: 'none'
});
const MetaDrawerNavigator = DrawerNavigator({
Home: {
screen: MetaTabNavigator,
navigationOptions: {
drawer: {
label: 'Drawer',
icon: ({ tintColor }) => <Icon name="rocket" size={24} />
},
},
}
},
{
contentComponent: props => <Menu {...props} />
}
);
AppRegistry.registerComponent('myApp', () => MetaDrawerNavigator);
MachineNavigator
const MachineNavigator = StackNavigator({
Main: {
screen: MachineOverview,
navigationOptions: ({ navigation }) => ({
title: "Dashboard",
headerLeft: (
<TouchableOpacity onPress={() => navigation.navigate("DrawerOpen")}>
<IOSIcon name="ios-menu" size={30} />
</TouchableOpacity>
),
headerStyle: { paddingRight: 10, paddingLeft: 10 }
})
},
Category: {
screen: Category,
navigationOptions: (props) => ({
title: "Kategorie",
})
},
ItemDetail: {
screen: ItemDetail,
navigationOptions: (props) => ({
title: "Video",
})
}
})
export default MachineNavigator;
According to this issue, you can add to the tab configuration the tabBarLabel property to control the label:
const MetaTabNavigator = TabNavigator({
Dashboard: {
screen: MachineNavigator, navigationOptions: {tabBarLabel: 'Dashboard'}
},
...