Header and Navigation-tab on a react-native application - react-native

I'm building my first react-native application, and I encountered a problem I could not solve.
on the home screen, I don't want any header, and on the other pages, I would like to keep the navigation option.
I want to build a simple home page, with I buttons sign-up and login, the problem is I can't hide the first header on any of the app pages, i dont know if the problem is in the header, or maybe in some other component?
please review the code below.
class HomeScreen extends React.Component {
static navigationOptions = {
header:null,
headerVisible:false
}
render() {
return (
<ImageBackground source = {backgroundImage} style = {styles.backgroundImage}>
<View style = {styles.container}>
<View style = {styles.btn_login}>
<Button title = "SIGNUP NOW" color='#69428F' onPress ={this._showSignUpPage}/>
</View>
<View style = {styles.btn_signup}>
<Button title = "LOGIN" color='#AAA3A3' onPress = {this._showLoginPage}/>
</View>
</View>
</ImageBackground>
);
}
class SignupScreen extends React.Component{
// this hides the navigation, and i cannot see the navigation
// static navigationOptions = {
// header:null,
// }
render(){
return (
<View style={styles.container_Signup}>
<Button title="SignupScreen"/>
<StatusBar barStyle="default" />
</View>
);
}
}
const AppStack = createStackNavigator(
{
Home:{
screen:HomeScreen,
navigationOptions:{
header:null
}
},
SIGNUP:SignupScreen,
LOGIN:LoginScreen
},
{
navigationOptions :{
header:null
}});
as you can see, I tried placing the header:null inside the class, and inside the stackNavigator, but nothing seems to work.

Try to set header mode none as follow:
const AppStack = createStackNavigator( {
Home:{
screen: HomeScreen,
navigationOptions: {
header: null
}
},
SIGNUP: SignupScreen,
LOGIN: LoginScreen
}, {
headerMode: "none"
});
I hope it help you.

Related

How to move tabBar when drawer is open in react-navigation

I use TabNavigator and DrawerNavigator both in my app.
When I open drawer with 'slide' option, contents slide with drawer but TabBar doesn't slide together.
I want to make TabBar slide together but I cannot find any option about it.
How Can I do this?
Could you help?
-------------[code]----------------
1) app.js
...skip ...
const DailySalesStack = createStackNavigator({
DailySalesMain: DailySalesMain,
},
{
defaultNavigationOptions:{
header:null
},
initialRouteName:'DailySalesMain'
});
const DailyRivalRankStack = createStackNavigator({
DailyRivalRankMain: DailyRivalRankMain,
},
{
defaultNavigationOptions:{
header:null
},
initialRouteName:'DailyRivalRankMain'
});
const SalesAnalysisStack = createStackNavigator({
SalesAnalysisMain: SalesAnalysisMain,
},
{
defaultNavigationOptions:{
header:null
},
initialRouteName:'SalesAnalysisMain'
});
const DailySalesAnalysisStack = createStackNavigator({
DailySalesAnalysisMain: DailySalesAnalysisMain,
},
{
defaultNavigationOptions:{
header:null
},
initialRouteName:'DailySalesAnalysisMain'
});
/// DRAWER!
const SalesStack = createDrawerNavigator({
DailySales: {
screen: DailySalesStack,
},
DailyRivalRank: {
screen: DailyRivalRankStack,
},
SalesAnalysis: {
screen: SalesAnalysisStack,
},
DailySalesAnalysis: {
screen: DailySalesAnalysisStack,
},
},
{
contentComponent:SalesSlideMenu,
drawerType: 'slide',
drawerWidth:230*REM,
}
);
...skip...
/// BOTTOM TAB
export default createAppContainer(createBottomTabNavigator(
{
MainStack:MainStack,
ApprovalStack:ApprovalStack,
SalesStack:SalesStack,
OrganizationStack:OrganizationStack,
SettingStack:SettingStack,
},
{
tabBarComponent: TabBar,
}
));
2) tabBar.js
const TAB_LIST = [
require('../../resources/images/tabIcon_main.png'),
require('../../resources/images/tabIcon_approval.png'),
require('../../resources/images/tabIcon_sales.png'),
require('../../resources/images/tabIcon_organization.png'),
require('../../resources/images/tabIcon_settings.png'),
];
export default class TabBar extends React.Component {
constructor(props) {
super(props);
}
render() {
console.log("[TabBar.js] : Render ====");
const {
onTabPress,
navigation
} = this.props;
const { routes, index: activeRouteIndex } = navigation.state;
return (
<SafeAreaView style={{backgroundColor:'rgb(250,250,250)'}}>
<View style={styles.rootContainer}>
{routes.map((route, routeIndex) => {
const isRouteActive = routeIndex === activeRouteIndex;
return (
<TouchableWithoutFeedback key={routeIndex} onPress={() => {onTabPress({ route });}}>
<View style={styles.tabIconContainer}>
<Image style={[styles.icon,isRouteActive&&{tintColor:'black'}]} source={TAB_LIST[routeIndex]} resizeMode={'contain'}/>
{/* <View style={[styles.badge]}><Text style={[styles.text,styles.badgeNumber]}>12</Text></View> */}
</View>
</TouchableWithoutFeedback>
);
})}
</View>
</SafeAreaView>
);
}
}
3) SlideMenu.js
const MENU_LIST = [
{'icon':require('../../resources/images/dailySales.png'),'label':'Daily Sales','subLabel':'','route':'DailySales'},
{'icon':require('../../resources/images/rivalRank.png'),'label':'Daily Rival Rank','subLabel':'','route':'DailyRivalRank'},
{'icon':require('../../resources/images/salesAnalysis.png'),'label':'Sales Analysis','subLabel':'','route':'SalesAnalysis'},
{'icon':require('../../resources/images/dailySalesAnalysis.png'),'label':'Daily Sales Analysis','subLabel':'','route':'DailySalesAnalysis'},
]
class SlideMenuTab extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<View style={{flex:0}}>
<TouchableWithoutFeedback onPress={()=>this.props.navigation.navigate(this.props.data.route+"Main")}>
<View style={[styles.tabContainer,this.props.focused&&{backgroundColor:'rgb(247,247,247)'}]}>
<Image style={styles.tabIcon} source={this.props.data.icon} resizeMode={'contain'}/>
<View style={styles.labelContainer}>
<Text style={[styles.text,styles.label]}>{this.props.data.label}</Text>
<Text style={[styles.text,styles.subLabel]}>{this.props.data.subLabel}</Text>
</View>
</View>
</TouchableWithoutFeedback>
</View>
)
}
}
export default class SalesSideMenu extends React.Component {
constructor(props) {
super(props);
console.log("[SalesSideMenu.js] : Constructor");
}
render() {
console.log("[SalesSideMenu.js] : render ====");
let menuList = [];
MENU_LIST.forEach((data)=>{
let focused = this.props.activeItemKey === data.route;
menuList.push(
<SlideMenuTab data={data} focused={focused} navigation={this.props.navigation}/>
);
})
return (
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<View style={styles.rootContainer}>
{menuList}
</View>
</SafeAreaView>
);
}
}
4) Screen with drawer
export default class DailySalesMain extends React.Component {
constructor(props) {
super(props);
}
render() {
console.log("[DailySalesMain.js] : render ====");
return (
<View style={{flex:1,backgroundColor:'white',alignItems:'center',justifyContent:'center'}}>
<TouchableWithoutFeedback onPress={()=>this.props.navigation.openDrawer()}>
<View style={{width:'100%',height:50}}>
<View style={{width:50,height:50,backgroundColor:'blue'}}></View>
</View>
</TouchableWithoutFeedback>
<Text>DailySalesMain</Text>
</View>
);
}
}
If youre ussing React Native... This should be the default behaviour at least in iOS. Android Material Design supports the Drawer as a design desition, so if you want to hide the TabBar, just make a custom one or include the TabBar inside the Drawer.
But warning, hidding the TabBar may sometimes bring errors in Apple Store when you upload your app for revision.
From the TabBar section in the Human Interface Guidelines of iOS....
Don't hide a tab bar when people navigate to different areas in your app. A tab bar enables global navigation for your app, so it should remain visible everywhere. The exception to this is in modal views. Because a modal view gives people a separate experience that they dismiss when they're finished, it's not part of the overall navigation of your app.
Use badging to communicate unobtrusively. You can display a badge—a red oval containing white text and either a number or an exclamation point—on a tab to indicate that new information is associated with that view or mode.
In other words.. if you plan to support iOS in your apps, you should try to always show the TabBar somehow, or the store might give you some usability complains like this one.
We noticed that several screens of your app were crowded or laid out in a way that made it difficult to use your app.
Please see attached screenshot for reference.
Next Steps
To resolve this issue, please revise your app to ensure that the content and controls on the screen are easy to read and interact with.

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.

Redirect to another screen after login. (React Native)

So I edited this with just one file; everything is there but I still can't seem to make it work.
Directory Structure:
LoginScreen.js
import { StackNavigator, } from 'react-navigation';
import DrawerScreen from '../Containers/Drawer.js';
// PJDS all-in
import HomeScreen from '../screens/HomeScreen.js';
import SettingsScreen from '../screens/SettingsScreen.js';
import { DrawerNavigator } from 'react-navigation';
const Navigation=DrawerNavigator({
Dashboard: {
screen: HomeScreen
},
Course: {
screen: SettingsScreen
},
})
// PJDS end
class LoginScreen extends Component {
constructor(props){
super(props)
}
showLogin(props){
let { onLogin, onLogout, onUser, handleSubmit, auth } = props
if(auth.access_token === '') {
return (
<View >
<Field style={styles.input} autoCapitalize="none" placeholder="Email Cu" component={TInput} name={'email'} />
<Field style={styles.input} autoCapitalize="none" placeholder="Password" secureTextEntry={true} component={TInput} name={'password'} />
<Button
title = "Login"
color = "#236CF5"
style = {{backgroundColor:'#F8F8F8'}}
onPress = {handleSubmit(onLogin)}
/>
</View>
)
}
else {
return (
<Navigation />
)
}
}
render(){
return this.showLogin(this.props)
}
}
After I click login, only a blank screen will appear. There are no errors but when I swipe to the right, no drawer will show up.
What is the problem here?
The navigate variable has not been defined anywhere in your method.
Since you've already bound your screens to react-navigation, navigator, therefore you can get access to the props this.props.navigation which in turn has a method navigate.
let { {/* Other props */}, navigation } = props
...
onPress={()=> navigation.navigate('theDrawer')}
You should assign a width to your drawerNavigator
const Navigation = DrawerNavigator({
Home: {
screen: Home
},
Login: {
screen: LoginScreen,
},
}, {
drawerWidth: 300,
drawerBackgroundColor: '#00234b',
contentOptions: {
inactiveTintColor: '#FAFAFA',
activeTintColor: '#2bbfed',
activeBackgroundColor: '#00152d',
labelStyle: {
fontFamily: 'Montserrat-Medium'
}
},
});
To access your drawer navigator you should do this:
.....
onPress={() => this.props.navigation.navigate('DrawerToggle')}

React Navigation StackNavigator not appearing when used inside another view

I'm attempting to use a React Navigation StackNavigator for a process that includes a static component at the top of the page and varying components at the bottom. The code I'm using is:
const Navigator = StackNavigator ({
splash: Splash,
prompt: Prompt,
pinCheck: PinCheck
}, {
initialRouteName: 'splash'
});
export default class Login extends React.Component
{
constructor (props)
{
super (props);
// code to set up animation state
}
componentDidMount()
{
// code to set up animation
}
finish_ (state)
{
this.props.navigation.navigate ('main', state);
}
render()
{
const screen = Dimensions.get('screen');
return (
<KeyboardAvoidingView style={Global.styles.verticalFill} ref={this.saveContainerRef}>
<ScrollView style={{flex: 1}} contentContainerStyle={{justifyContent: 'space-between'}}>
<Animated.View style={{opacity:this.state.fade1,alignItems:'center'}} >
<Image
style={{width:screen.width * 0.6,height: screen.height*0.55}}
source={imgLogo}
resizeMode='contain'
/>
<Navigator />
</Animated.View>
</ScrollView>
</KeyboardAvoidingView>
);
}
}
When I run this, however, my initial route component is not shown. It works correctly if I swap <Navigator/> to <Splash/> however, so the component itself definitely works in this context.
Any ideas what's wrong?
There is a problem in your navigation setup.
All the routes in the StackNavigator must declare a screen
as mentioned in the docs
const Navigator = StackNavigator ({
splash: {
screen: splash
},
prompt: {
screen: prompt
},
pinCheck: {
screen: pinCheck
}
}, {
initialRouteName: 'splash'
})

Open Drawer by clicking in header of containing StackNavigator

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
}
})