I am using ReactNavigation and after SignIn , i enter my home page. My home page has 4 tabs, and on 4th tab i have logout button. After clicking on logout button , i should get back to SIGN IN screen.
The issue i am facing is , i am not been able to reset the TAB NAVIGATOR.
this.props.navigation.dispatch({
type: NavigationActions.NAVIGATE,
routeName: 'SignIn',
action: {
type: NavigationActions.RESET,
index: 0,
actions: [{type: NavigationActions.NAVIGATE, routeName: 'SignIn'}]
}
})
I tried applying above chunk of code to navigate , but it did not work. Please tell me , how to get out of tab navigator.
Your root-level navigation should be a StackNavigator with children looking something like this:
Welcome screen
Login screen
Tab Navigator (for logged in home screen)
Tab 1
Tab 2
Tab 3
Tab 4 (with logout button)
To reset the TabNavigator, you shouldn't dispatch an action of type NavigationActions.NAVIGATE because that will push onto the current navigation stack, instead of removing the tab navigator from the state. Instead, consider using a Reset action. So the code within your logout function should have:
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Login'})
]
})
this.props.navigation.dispatch(resetAction);
onPress of Logout we are calling below code
const resetAction = NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "SignIn" })],
key: null
});
this.props.navigation.dispatch(resetAction);
This is our AppNavigation file is there any way to reset app on Logout
const PrimaryNav = StackNavigator(
{
SignIn: {
screen: SignIn,
navigationOptions: {
headerMode: "none",
header: null
}
},
SignUp: {
screen: SignUp,
navigationOptions: {
headerMode: "none",
header: null
}
},
TabsScreen: {
screen: TabsScreen,
navigationOptions: {
headerMode: "float",
headerTitleStyle: { color: "#ffffff" },
gesturesEnabled: true,
header: null,
}
},
)
export const sideMenuStack = StackNavigator({
SideMenu: {
screen: SideMenu,
navigationOptions: {
headerMode: "none",
header: null
}
},
Settings: {
screen: Settings,
navigationOptions: ({ navigation }) => ({
title: "Settings",
})
},
SignIn: {
screen: SignIn,
navigationOptions: {
headerMode: "none",
header: null
}
},
)
export const FeedsStack = StackNavigator({
FeedsStack: {
screen: FeedsStack,
navigationOptions: {
headerMode: "none",
header: null
}
},
Post: {
screen: Post,
navigationOptions: ({ navigation }) => ({
title: "Post",
})
},
)
export const UserStack = StackNavigator({
UserStack: {
screen: UserStack,
navigationOptions: {
headerMode: "none",
header: null
}
},
Friends: {
screen: Friends,
navigationOptions: ({ navigation }) => ({
title: "Friends",
})
},
)
export const TabView = TabNavigator(
{
FeedsStack: {
screen: FeedsStack,
navigationOptions: {
tabBarLabel: "Feeds",
scrollEnabled: true,
focussed: true,
tabBarIcon: ({ tintColor }) =>
<Image
source={Images.feedsActive}
style={[styles.icon, { tintColor: tintColor }]}
/>
}
},
UserStack: {
screen: UserStack,
navigationOptions: {
tabBarLabel: "Users",
tabBarIcon: ({ tintColor }) =>
<Image
source={Images.UserActive}
style={[styles.icon, { tintColor: tintColor }]}
/>
}
},
sideMenuStack: {
screen: sideMenuStack,
navigationOptions: {
tabBarLabel: "More",
headerMode: "screen",
tabBarIcon: ({ tintColor }) =>
<Image
source={Images.moreActive}
style={[styles.icon, { tintColor: tintColor }]}
/>
}
}
},
//Default configurations for Tabs
{
tabBarPosition: "bottom",
animationEnabled: true,
tabBarOptions: {
indicatorStyle:{
borderBottomColor:'#32a1fe',
borderBottomWidth:3
},
showLabel: true,
backBehavior: "none",
showIcon: true,
activeTintColor:"#338AD8",
inactiveTintColor:"#BEC5CB",
upperCaseLabel:false,
labelStyle :[styles.labelStyle],
}
}
);
Related
Im making an app in React Native, and am looking to have a page that displays the bottom navigation bar but isn't directly on that navigation bar, i.e. it is sort of a child of another page though does not need to be access through the bottom Nav.
However, whenever I take it out of the bottom tab navigator it won't hide the icon, and if it is not added it wont allow me to see the bottom nav when I go to that page.
The code is as follows;
{
History: {
screen: HistoryScreen,
navigationOptions: {
tabBarIcon: ({ focused, tintColor }) =>
<Icon
focused={focused}
color={{ tintColor }}
name="history"
size={20}
zIdex="13"
solid
/>
}
},
Home: {
screen: HomeScreen,
navigationOptions: {
tabBarIcon: ({ focused, tintColor }) =>
<Icon
focused={focused}
color={ Colors.gyroscopicOrgane }
name="home"
size={20}
zIdex="13"
solid
/>
}
},
ConcreteTest: {
screen: ConcreteTestScreen,
navigationOptions: {
tabBarIcon: ({ focused,tintColor }) => <
Icon name="cog"
focused={focused}
color={{ tintColor }}
size={20}
zIdex="13"
solid
/>
}
},
Settings: {
screen: SettingsScreen,
navigationOptions: {
tabBarIcon: ({ }) => {
showIcon: false
}
}
}
},
{
tabBarOptions: {
activeTintColor: "#E66F25",
inactiveTintColor: "#B8BBC4",
showLabel: false
}
}
)
const AppStack = createStackNavigator({
Home: HomeScreen,
History: HistoryScreen,
ConcreteTest: ConcreteTestScreen,
Settings: SettingsScreen,
});
const AuthStack = createStackNavigator({
Launch: LaunchScreen,
Login: LoginScreen,
SignUp: SignUpScreen
});
export default createAppContainer(
createSwitchNavigator(
{
Loading: LoadingScreen,
Launch: LaunchScreen,
Settings: SettingsScreen,
App: AppTabNavigator,
Features: AppStack,
Auth: AuthStack
},
{
initialRouteName: "Loading"
}
)
)
It might be helpful to attach a screenshot of your layout. Try positioning your element absolutely (position: absolute) and then using top: left: bottom: right: to align it. If you need it to display conditionally, try setting a variable elementVar = null; and then if (needs to be displayed) {elementVar = YOUR_ELEMENT_CONTENT} then simply use {elementVar} in your render(return()) function.
I have three navigators, AuthStackNavigator for Auth, and DrawerNavigator and AppStackNavigator. So AuthStackNavigator is nested to DrawerNavigator and DrawerNavigator is nested to AppStackNavigator.
The problem is , When navigating from DrawerNavigator to AppStackNavigator, it continues to show header titles of DrawerNavigator , But expected is header titles of AppStackNavigator. ( As of now i have mentioned header:null as it shows dual header ) How to solve this issues ?
Navigators code:
const AppStackNavigator = createStackNavigator({
Home: {
screen: Home,
navigationOptions: {
header: null
}
},
StoreList: {
screen: StoreList,
navigationOptions: {
header: null
}
},
});
const DrawerNavigator = createDrawerNavigator({
Dashboard: {
screen: AppStackNavigator,
navigationOptions: {
drawerLabel: "Home",
}
},
Training: {
screen: Training,
navigationOptions: {
drawerLabel: "Training"
}
},
RoutePlan: {
screen: RouteCalendar,
navigationOptions: {
drawerLabel: "Route Plan"
}
}
},
{
contentOptions: {
activeTintColor: '#127CC1',
},
contentComponent: props => <DrawerComponent {...props}/>,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
navigationOptions : ({navigation}) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = routeName;
return {
headerTitle,
headerLeft: (
<Icon name="md-menu" style={{ marginLeft: 10 }}
onPress={() => navigation.toggleDrawer()}
/>
)
}
}
}
);
const AuthStackNavigator = createStackNavigator(
{
LoginScreen: {
screen: Login,
navigationOptions: {
headerTransparent: true
}
},
Drawer: DrawerNavigator,
});
Please guide me through this !
In my React-native project, I am using drawer navigation. I have set the some screen inside the Drawer navigation and some of the screens outside the Drawer navigation.
I have declared a class named HomeDrawer, for this set up. Here's the code of that class.
HomeDrawer.js
class NavigationDrawerStructure extends React.Component {
constructor() {
super();
this.state = {
ModalVisibleStatus: false,
}
};
static navigationOptions = {
header: null ,
};
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row', marginLeft:5 }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
<Image style={{width:20, height:20, margin:5, justifyContent:'center'}} source={require('../assets/menu.png')} />
</TouchableOpacity>
</View>
);
}
}
const FirstActivity_StackNavigator = createStackNavigator({
First: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
title: 'Home',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />
),
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
ScreenInternal: {
screen: BookDetails,
navigationOptions: ({ navigation }) => ({
title: 'Screen With Navigation Drawer',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Screen2_StackNavigator = createStackNavigator({
Second: {
screen: CategoryBrowse,
navigationOptions: ({ navigation }) => ({
title: 'Create Note',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Drawer = createDrawerNavigator({
Screen1: {
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: (
<Icon name='home' size={25}
/>
)
},
},
Screen2: {
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Category',
drawerIcon: (
<Image source={require('../assets/splash.png')}
style={{height:25, width:25,}}
/>
)
},
},
},
{
contentComponent: CustomSidebarMenu,
//Sidebar width
drawerWidth: Dimensions.get('window').width - 130,
},
);
const Drawer2 = createDrawerNavigator({
Screen1: {
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: (
<Icon name='home' size={25}
/>
)
},
},
Screen2: {
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Category',
drawerIcon: (
<Image source={require('../assets/splash.png')}
style={{height:25, width:25,}}
/>
)
},
},
},
{
drawerType: 'back',
drawerPosition: 'right',
drawerWidth: 200,
drawerBackgroundColor: 'orange',
//For the Custom sidebar menu we have to provide our CustomSidebarMenu
contentComponent: CustomSidebarMenu,
//Sidebar width
drawerWidth: Dimensions.get('window').width - 130,
},
);
const DrawerNavigatorExample = createStackNavigator({
Drawer: { screen: Drawer, navigationOptions: { header: null } },
BookDetails: {
screen: BookDetails,
navigationOptions: { title: 'Book Details' },
},
CartPage: {
screen: CartPage,
navigationOptions: { title: 'Cart Page' },
},
},
);
In the above code, you can see that I have an internal screen named 'HomeScreen' and one external screen of drawer named 'BookDetails'. I have also set the navigationOptions title for the screens.
Now, in the HomeScreen I have a click event , by pressing on e element I pass a value and start the external screen 'BookDetails'. Here's the code for that-
<TouchableOpacity style={{flexDirection:'row'}}
onPress={() => this.props.navigation.navigate('BookDetails', {
JSON_ListView_Clicked_Item: item.id,
})}
>
Now, in the BookDetails screen I want to change the navigation header title according to the value I receive from HomeScreen.
Here's my code of the BookDetails Screen-
BookDetails.js
class BookDetails extends Component {
constructor() {
super()
this.state= {
dataSource : [],
isLoading: true,
bookId: '',
responseDetails:'',
loading: true
}
}
async componentDidMount() {
const { navigation } = this.props;
this.focusListener = navigation.addListener("didFocus", () => {
this.getBookDetailsApi();
});
this.setState({
bookId:(
this.props.navigation.state.params.JSON_ListView_Clicked_Item
? this.props.navigation.state.params.JSON_ListView_Clicked_Item
: 'No Value Passed'
)
})
}
async componentWillMount() {
await Font.loadAsync ({
Roboto: require('native-base/Fonts/Roboto.ttf'),
Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf')
});
this.setState({loading:false});
}
getBookDetailsApi() {
const url = 'my url';
return fetch(url, {
method: 'GET',
headers: new Headers({
'Content-Type' : 'application/json',
'app_api_key': APP_API_KEY,
})
})
.then((response)=> response.json() )
.then((responseJson) => {
console.log('####:'+responseJson.nameEnglish)
this.setState({
responseDetails: responseJson,
isLoading: false,
})
})
.catch((Error) => {
console.log(Error)
});
};
}
render() {
if(this.state.loading) {
return(
<Root>
<AppLoading/>
</Root>
);
}
return (
<View style={styles.container}>
<TouchableOpacity
onPress = {()=>{
this.props.navigation.navigate('CartPage')
}}
>
<Text style={styles.title}>Hello Splash</Text>
</TouchableOpacity>
</View>
);
}
}
export default BookDetails;
Now, I need a solution to keep the BookDetails Screen navigation header title dynamic and keep changing it according to the values I receive from HomeScreen. So, it would be very nice if someone give a solution to that.
In my React-Native project I am using one Navigation drawer. In that drawer I declared two screens - NoteMeHome and MakeNote. Initially the NoteMeHome starts as an initial route of Drawer Navigation. From the NoteMeHome.js (first screen) class I go to the MakeNote.js (Second Screen). In this MakeNote.js class I have used one form to fill. After filling the Form when user clikcs submit it will go back to the previos Screen ( NoteMeHome.js) and as there is an API call in this NoteMeHome.js class, it will refresh and show the submitted data.
But whenever I am going from MakeNote Screen to NoteMeHome Screen, It just changes to back stack but the the NoteMeHome Screen is not refreshed as it is showing the old data.
To control the Drawer flow and structure I have created a class named -
NavigationDrawerStructure.js
class NavigationDrawerStructure extends Component {
static navigationOptions = {
header: null ,
};
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
{/*Donute Button Image */}
<Icon name='menu'/>
</TouchableOpacity>
</View>
);
}
}
const FirstActivity_StackNavigator = createStackNavigator({
First: {
screen: NoteMeHome,
navigationOptions: ({ navigation }) => ({
title: 'Home',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Screen2_StackNavigator = createStackNavigator({
Second: {
screen: MakeNote,
navigationOptions: ({ navigation }) => ({
title: 'Create Note',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Drawer = createDrawerNavigator({
Screen1: {
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: (
<Icon name='home' size={24}
/>
)
},
},
Screen2: {
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Create Note',
drawerIcon: (
<Icon name='home' size={24}
/>
)
},
},
});
const DrawerNavigatorExample = createStackNavigator({
Drawer: { screen: Drawer, navigationOptions: { header: null } },
ScreenExternal: {
screen: ScreenExternal,
navigationOptions: { title: 'Screen External' },
},
});
export default createAppContainer(DrawerNavigatorExample);
In the MakeNote.js(Second Screen) I use one function submit to a POST request. Here's the code for that-
submit() {
this.setState({isLoading:true})
let collection = {}
collection.timestamp = this.state.timestamp,
collection.status = this.state.status,
collection.title = this.state.title,
collection.detail = this.state.detail,
collection.url = this.state.url,
collection.mail = this.state.mail,
collection.phone = this.state.phone,
collection.category = this.state.category
console.log('#HELLO:', collection);
var url = 'my url';
if(collection.title != '' ) {
if(this.state.isNetConnected != false) {
fetch(url, {
method: 'POST',
body: JSON.stringify(collection),
headers: new Headers({
'Content-Type' : 'application/json',
'token': 'abcd',
'jwt': this.state.getValue
})
}).then(response =>
{
this.setState({isLoading:false});
if (response.status !== 200) {
console.log('Status Code: ' + response.status);
return;
}
response.json().then(data =>{
console.log(data);
if(data.status == "saved") {
this.props.navigation.navigate('First');
}
});
}
)
.catch(error=>{
this.setState({isLoading:false})
console.error('Error:', error)
})
} else{
this.setState({isLoading:false});
Alert.alert("Oops!! No Internet Connection Available");
}
}
else {
this.setState({isLoading:false})
Alert.alert('Please fill up the required field');
}
}
In the submit function you can see the below line initialize the previous screen back-
if(data.status == "saved") {
this.props.navigation.navigate('First');
}
It shows the NoteMeHome(First Screen) back but no data has been refreshed.
So, I need a solution to refresh this NoteMeHome Screen and show the latest data by API call.
You can pass a callback function as parameter when you call navigate .
Inplace of :
this.props.navigation.navigate('First');
Add This:
this.props.navigation.navigate('First', {
onGoBack: () => this.refresh(),
});
Then add callback function :
refresh() {
this.doSomething();
}
Hope it helps !
I have simple createBottomTabNavigator and one of it's tabs is createStackNavigator and inside this stack I have one screen which I want it to over lap the tab bar. I tried use tabBarVisible: false on this screen but no luck there.
Code:
const BookingsStack = createStackNavigator({
Commutes: {
screen: Commutes,
navigationOptions: {
title: "Commutes",
header: null,
}
},
Tickets: {
screen: Tickets,
navigationOptions: {
title: "Tickets",
header: null,
tabBarVisible: false
}
}
});
export const MainNav = createBottomTabNavigator({
Current: {
screen: Current,
navigationOptions: {
title: "Current",
tabBarIcon: ({ tintColor }) => (
<IconIO name="ios-bus" size={scale(20)} color={tintColor} />
)
}
},
BookingsStack: {
screen: BookingsStack,
navigationOptions: {
title: "Commutes",
tabBarIcon: ({ tintColor }) => (
<IconSL name="layers" size={scale(20)} color={tintColor} />
)
}
}
}
As given in the navigation document:
If we want to hide the tab bar when we navigate from the feed home to a details screen without shuffling navigators, we cannot set the tabBarVisible: false configuration in navigationOptions on DetailsScreen, because those options will only apply to the FeedStack. Instead, we can do the following:
const FeedStack = createStackNavigator({ FeedHome: FeedScreen,
Details: DetailsScreen, });
FeedStack.navigationOptions = ({ navigation }) => { let
tabBarVisible = true; if (navigation.state.index > 0) {
tabBarVisible = false; }
return {
tabBarVisible,
}; };
I found a solution in the react-navigation docs - the implementation look like this:
const ChildMainNav = createBottomTabNavigator({
Current: {
screen: Current,
navigationOptions: {
title: "Current",
tabBarIcon: ({ tintColor }) => (
<IconIO name="ios-bus" size={scale(20)} color={tintColor} />
)
}
},
Commutes: {
screen: Commutes,
navigationOptions: {
title: "Commutes",
tabBarIcon: ({ tintColor }) => (
<IconSL name="layers" size={scale(20)} color={tintColor} />
)
}
}
}
export const MainNav = createStackNavigator({
ChildMainNav: {
screen: ChildMainNav,
navigationOptions: {
header: null
}
},
// overlap screens
Tickets: {
screen: Tickets,
navigationOptions: {
title: "Tickets",
header: null,
tabBarVisible: false
}
}
});
The idea is to add the Tab navigator into Stack navigator and add in this stack any other screens you want to have different navigationOptions to overlap the ones in your Tab.
Link to docs under:
A tab navigator contains a stack and you want to hide the tab bar on specific screens