React-Navigation Drawer and Static Tab-Navigation - react-native

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'}
},
...

Related

react-navigation goBack between stack navigators

In my React native app I am using "react-navigation": "^3.11.0".
I have top level bottomTabNavigator
const TabNavigator = createBottomTabNavigator({
Main: {
screen: balanceStack,
navigationOptions: {
tabBarLabel: I18n.t("balanceTabLabel"),
tabBarIcon: ({ tintColor}: {tintColor: string}) => (
<Icon name="home" style={{color: tintColor}} />
)
}
},
ServicesStack: {
screen: servicesStack,
navigationOptions: {
tabBarLabel: I18n.t("servicesTabLabel"),
tabBarIcon: ({ tintColor}: {tintColor: string}) => (
<Icon name="list-box" style={{color: tintColor}} />
)
}
},
}, {
tabBarOptions: {
activeTintColor: WHITE_COLOR,
inactiveTintColor: WHITE_COLOR,
style: {
backgroundColor: PRIMARY_COLOR,
}
},
backBehavior: 'history',
swipeEnabled: true,
});
And stack navigators for each tab:
const balanceStack = createStackNavigator({
Balance: {
screen: MainScreen,
},
FullBalance: {
screen: FullBalanceScreen,
},
Payment: {
screen: PaymentScreen,
},
ServiceView: {
screen: ViewServiceScreen,
},
}, {
initialRouteName: 'Balance',
headerMode: 'none',
});
const servicesStack = createStackNavigator({
AllServices: {
screen: AllServicesScreen,
},
ServiceView: {
screen: ViewServiceScreen,
},
ServiceOptionAction: {
screen: ServiceOptionsActionScreen,
}
}, {
initialRouteName: 'AllServices',
headerMode: 'none',
});
I want that my navigation for all tabs will be common, not divided per stack.
For example
when I navigate
Balance->FullBalanceScreen->AllServices(by clicking Services tab)->ServiceView
If I click back button (call goBack()) one time I will back to AllServices. But if I click back second time, I don't navigate to FullBalanceScreen, because it's in another stack. How can I do this?
Finally, I didn't find solution with TabNavigator and replace it with top level StackNavigator.
Also I use custom bottom Tabs component and set onPress for tab button to
onPress () {
        this.props.navigation.navigate (this.props.navigateRouteName)
    }
Where navigateRouteName is routeName to target stack route.
If you define a custom header (either for the top level nav, or duplicated for each stack) then navigation object will have the global history (not just for each stack) so clicking back will jump between tabs
<A.Navigation screenOptions={{header: ({nav}) => <CustomHeader nav/>}>
and in you header you can conditionally show a back button and add handler
if (nav.canGoBack()) // show button
... nav.goBack() // onPress

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',
}
);

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

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
}

react navigation back button back to spalsh screen

I want to use react navigation in react native project but when I use this code in header it shows some back button in every screen and when I click on this it goes back to the splash screen. How to use react navigation with check first splash and then go to stack home and show back button in any screen.its very confuse me.
const TabNav=createBottomTabNavigator({
Notification:{
screen:Notif,
navigationOptions: () => ({
title:'',
tabBarIcon: ({ tintColor }) => {
return (
<IconIonicons
name='ios-notifications'
size={40}
color={tintColor}
/>
);
},
tabBarOptions: {
activeTintColor: '#000',
}
})
},
Home:{
screen:Home3,
navigationOptions: () => ({
title:'',
tabBarIcon: ({ tintColor }) => {
return (
<Image style={{ width: 40, height: 40,marginTop:'20%' }} source={Home}/>
);
}
})
},
User:{
screen:ProfileScreen,
navigationOptions: () => ({
title:'',
tabBarIcon: ({ tintColor }) => {
return (
<IconIonicons
name='ios-person'
size={40}
color={tintColor}
/>
);
},
tabBarOptions: {
activeTintColor: '#000',
}
})
},
},
{
initialRouteName:"Home"
},{
header: null,
headerMode: 'none',
}
)
const StackHome = createStackNavigator({
Tabs:{
screen:TabNav
},
CardView:{
screen:CardView,
},
Thumb:{
screen:Thumb,
}, Item:{
screen:Item,
}, Product:{
screen:ProductScreen,
}, Festivals:{
screen:Festivals,
} , Review:{
screen:Review,
} , Movie:{
screen:Movie,
} , Naghd:{
screen:Naghd,
} , Advertisment:{
screen:Advertisment,
} , Advertis:{
screen:Advertis,
}, CreateAd:{
screen:CreateAd,
}, Insta:{
screen:Insta,
}, Test:{
screen:Test,
}, ForoshRah:{
screen:ForoshRah,
}, Home2:{
screen:Home2,
}, Login:{
screen:Login,
}, Elan:{
screen:Elan,
}, Sabtenam:{
screen:Sabtenam,
}, sponser:{
screen:sponsor,
},Splash:{
screen:Spalsh
},Products:{
screen:Products
},
initialRouteName : 'Home',
},{
headerMode:'none',
navigationOptions: {
header: (props) => <ImageHeader {...props} />,
}
}
)
const RootNav = createStackNavigator({
StackHome:{
screen:StackHome
},
Splash:{
screen:Spalsh
},Login:{
screen:Login
},
},{
initialRouteName : 'Splash',
header: null,
});
You can use SwitchNavigator of React Navigation. As the SwitchNavigator is to only ever show one screen at a time. By default, it does not handle back actions and it resets routes to their default state when you switch away.
Kindly refer this https://reactnavigation.org/docs/en/switch-navigator.html
Remove the **Splash** Screen from your **StackHome** StackNavigator
Alter your **RootNav** with Switch Navigator like below
// Uses SwitchNavigator
const RootNav = createSwitchNavigator({
StackHome:{
screen: StackHome
},
Splash:{
screen: Splash
},Login:{
screen: Login
},
},{
initialRouteName : 'Splash'
});
Your StackHome consist of some stack navigators screens, you can set the navigation options from there itself to set the image in the header. You can set like below.
const StackHome = createStackNavigator({
CardView:{
screen: CardView,
navigationOptions: ({ navigation }) => ({
headerTitleStyle: { flex: 1, fontWeight: 'normal', fontSize: 15, color: '#FFFFFF', fontFamily: 'DroidSans-Bold' },
headerTintColor: "#2662b2",
headerStyle: {
backgroundColor: "#05BFFF",
},
headerRight:(<View><NotificationComponent navigation={navigation}/></View>)
})
},
Thumb:{
screen: Thumb,
}, Item:{
screen: Item,
}
});

How to force drawer to be over header with react navigation

I saw other answers regarding this issue but I can't find solution.
I want to show drawer always above app screen and above header. Instead drawer is always bellow header.
What am I doing wrong here:
const AppNavigation = createStackNavigator(
{
Main: { screen: Main, navigationOptions: {
title: "Main"
} },
Home: { screen: Home, navigationOptions: {
title: "Home"
} }
},
{
initialRouteName: "Main"
}
);
const DrawerNavigation = createDrawerNavigator(
{
Home: Home,
Main: Main
},
{
initialRouteName: "Main"
}
);
App = createStackNavigator({
drawer: {
screen: DrawerNavigation,
},
app: {
screen: AppNavigation
}
}, {
initialRouteName: 'drawer',
navigationOptions: ({navigation}) => ({
headerStyle: {backgroundColor: '#a9a9a9'},
title: 'Welcome!',
headerTintColor: 'white',
headerLeft: <Text onPress={() =>
navigation.dispatch(DrawerActions.toggleDrawer())}>Menu</Text>
})
});
export default () => (
<View style={{ flex: 1 }}>
<App />
</View>
Our app is similar to this. You can make the drawer be over the header with react-navigation if it is the <Root /> component of your app (the one you import into index.js). For example:
export const Root = DrawerNavigator({
Tabs: {
screen: Tabs,
title: 'Tabs'
},
STACK1: {
screen: STACK1,
title: 'STACK1',
},
STACK2: {
screen: STACK2,
title: 'STACK2',
},
});
That will give you something like this: