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

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.

Related

Header and Navigation-tab on a react-native application

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.

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>

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

Flux (alt), TabBarIOS, and Listeners and tabs that have not yet been touched / loaded

I've got a problem that I'm sure has a simple solution, but I'm new to React and React Native so I'm not sure what I'm missing.
My app has a TabBarIOS component at its root, with two tabs: TabA and TabB. TabB is subscribed to events from a Flux store (I'm using alt) that TabA creates. TabA basically enqueues items that TabB plays. This part of the code is fine and works as expected.
The problem is that TabA is the default tab so the user can use TabA an enqueue items, but because TabB hasn't been touched/clicked the TabB component hasn't been created so it's listener hasn't been registered. Only when TabB is pressed does it get created and correctly receive events.
So how can I ensure the TabB component gets created when the TabBarIOS component is rendered? Do I need to something hacky like set the active tab to TabB on initial load and flip it back to TabA before the user does anything?
Yes, you'll need to do something hacky if you're not using a Navigator component. If you're using Navigatoryou can specify a set of routes to initially mount with the initialRouteStackprop. This is however going to need you to modify a bit the way your app works I think.
If not using Navigator, you'll indeed have to do something hacky as you suggested. I've set up a working example here based on RN's TabBar example.
Below you'll find the code of this example, check the console.log (they don't seem to work on rnplay) to see that that components are mounted on opening the app.
Example Code
var React = require('react-native');
var {
AppRegistry,
Component,
Image,
StyleSheet,
TabBarIOS,
Text,
View
} = React;
import _ from 'lodash';
var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
class StackOverflowApp extends Component {
constructor(props) {
super(props);
this.state = {
selectedTab: 'blueTab',
notifCount: 0,
presses: 0
};
}
_renderContent = (color, pageText, num) => {
return (
<View style={[styles.tabContent, {backgroundColor: color}]}>
<Text style={styles.tabText}>{pageText}</Text>
<Text style={styles.tabText}>{num} re-renders of the {pageText}</Text>
</View>
);
};
componentWillMount() {
this.setState({selectedTab: 'redTab'});
}
componentDidMount() {
this.setState({selectedTab: 'blueTab'});
}
render () {
return (
<View style={{flex: 1}}>
<TabBarIOS
tintColor="white"
barTintColor="darkslateblue">
<TabBarIOS.Item
title="Blue Tab"
icon={{uri: base64Icon, scale: 3}}
selected={this.state.selectedTab === 'blueTab'}
onPress={() => {
this.setState({
selectedTab: 'blueTab',
});
}}>
<Page1 />
</TabBarIOS.Item>
<TabBarIOS.Item
systemIcon="history"
badge={this.state.notifCount > 0 ? this.state.notifCount : undefined}
selected={this.state.selectedTab === 'redTab'}
onPress={() => {
this.setState({
selectedTab: 'redTab'
});
}}>
<Page2 />
</TabBarIOS.Item>
</TabBarIOS>
</View>
);
};
}
class Page1 extends Component {
static route() {
return {
component: Page1
}
};
constructor(props) {
super(props);
}
componentWillMount() {
console.log('page 1 mount');
}
componentWillUnmount() {
console.log('page 1 unmount');
}
render() {
return (
<View style={styles.tabContent}>
<Text style={styles.tabText}>Page 1</Text>
</View>
);
}
}
class Page2 extends Component {
static route() {
return {
component: Page2
}
};
constructor(props) {
super(props);
}
componentWillMount() {
console.log('page 2 mount');
}
componentWillUnmount() {
console.log('page 2 unmount');
}
render() {
return (
<View style={styles.tabContent}>
<Text style={styles.tabText}>Page 2</Text>
</View>
);
}
}
const styles = StyleSheet.create({
tabContent: {
flex: 1,
backgroundColor: 'green',
alignItems: 'center',
},
tabText: {
color: 'white',
margin: 50,
},
});
AppRegistry.registerComponent('StackOverflowApp', () => StackOverflowApp);