I want to be able to have badges for one of the icons for my bottom tabs (Reminders) but i do not know how to pass the value such that the badge will show the number from the value given from the reminderscreen.
So how would I go about this? Im quite confused with how react navigation works. Any help would be much appreciated! Thanks!
In App.js
const TabStack = createBottomTabNavigator(
{
Home : { screen: HomeStack },
Reminders: { screen: ReminderStack,
navigationOptions: ({ screenProps }) => ({
tabBarIcon: ({tintColor}) =>
<View style={{flexDirection: 'row',alignItems: 'center',justifyContent: 'center',}}>
<IconBadge
MainElement={
<View style={{
marginRight:15
}}>
<Ionicons name={`ios-alarm`} size={30} color={tintColor} />
</View>
}
BadgeElement={
<Text style={{color:'#FFFFFF'}}>{screenProps.notifCount}</Text>
}
Hidden={true}
IconBadgeStyle={
{width:20,
height:20,
backgroundColor: 'red'}
}
/>
</View>
})
},
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons;
let iconName;
if (routeName === 'Home') {
iconName = `ios-home`;
} else if (routeName === 'Reminders') {
iconName = `ios-alarm`;
}
return <IconComponent name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: '#0892d0',
inactiveTintColor: 'gray',
},
}
);
In ReminderScreen.js
import React from 'react';
import { Text, View, TouchableOpacity, StyleSheet,Image,ScrollView,Dimensions} from 'react-native';
import { ListItem, withBadge,Badge, } from 'react-native-elements';
import { Container, Header, Tab, Tabs, ScrollableTab } from 'native-base';
import R_Equipment from './rEquipmentTab';
import R_Room from './rRoomTab';
import axios from 'axios';
export default class ReminderScreen extends React.Component {
render() {
return (
//I want to pass a notifCount variable back to Tabstack
//e.g. notifCount = 5
<Container>
<Tabs renderTabBar={()=> <ScrollableTab />}>
<Tab heading="Rooms">
<R_Room navigation={this.props.navigation} />
</Tab>
<Tab heading="Equipment">
<R_Equipment navigation={this.props.navigation} />
</Tab>
</Tabs>
</Container>
);
}
}
const styles = StyleSheet.create({
displayImage: {
height: 50,
width: 100,
borderRadius: 10,
},
});
You can send it as parent to child, or you can use state, if it's easier you can use Redux
//This use vanilla.js or state common
<YourComponent = badgeData={this.state.badgedata} />
// In your second class/child, get the data as props
this.props.badgeData
Or for more detail, you cant follow the link below :
Here
Related
How to add submenu or tabs in the upper part in connection with the lower button and show the name of the lower button in the header of the application.
import React from 'react';
import { createStackNavigator } from 'react-navigation-stack';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { createAppContainer } from 'react-navigation';
import { MaterialIcons, MaterialCommunityIcons } from '#expo/vector-icons';
import Splash from '../screens/Splash';
import NewsListScreen from '../screens/NewsListScreen';
import NewsItemScreen from '../screens/NewsItemScreen';
const StackNavigator = createStackNavigator({
//Splash: {screen: Splash},
News: {
screen: NewsListScreen
},
NewsItem: {
screen: NewsItemScreen,
navigationOptions: {
headerTitle: 'News Item'
}
}
});
const BottomTabNavigator = createBottomTabNavigator({
Home: {
screen: StackNavigator,
navigationOptions: {
tabBarIcon: () => <MaterialIcons name="home" size={24} />
}
},
News: {
screen: StackNavigator,
navigationOptions: {
tabBarIcon: () => <MaterialCommunityIcons name="newspaper-variant-outline" size={24} />
}
}
})
export default createAppContainer(BottomTabNavigator);
What I want to achieve is the following:
As you can see, the bottom button [News] has three referential buttons in the upper part [FEATURED], [RELEVANT], [SEARCH] and, in addition to that, it recovers the name of the bottom button and adds it to the application header below the top buttons.
[EDITED]
Your NewsListScreen screen, instead of just being a tab bar component, can be something like that:
function NewsListScreen = (props) => (
<View>
<Text>News</Text>
<TabBarComponent {...props} />
</View>
)
function TabBarComponent = createMaterialTopTabNavigator({
featured: ... ,
relevant: ... ,
search: ... ,
})
That being said, if you can, you should update your project to react navigation v5, which is I think much more user friendly.
Final Output:
Implementation using react-navigation v5 :
import * as React from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import {
NavigationContainer,
useNavigationState,
} from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
const TopTab = createMaterialTopTabNavigator();
const BottomTab = createBottomTabNavigator();
/*
Here I am using MaterialTopTabNavigator instead of StackNavigator,
which is a better choice based on UI snapshot in this case.
*/
function NewsTopTabs() {
/*
in case you want to set the title dynamically then you can use the
useNavigationState hook but as there are just two bottom tabs so
I am using hardcoded values.
*/
const nav = useNavigationState((state) => state);
return (
<>
<View style={styles.titleBar}>
<Text style={styles.title}>News</Text>
</View>
<TopTab.Navigator>
<TopTab.Screen name="Featured" component={Featured} />
<TopTab.Screen name="Relevant" component={Relevant} />
<TopTab.Screen name="Search" component={Search} />
</TopTab.Navigator>
</>
);
}
function MatchesTopTabs() {
return (
<>
<View style={styles.titleBar}>
<Text style={styles.title}>Matches</Text>
</View>
<TopTab.Navigator>
<TopTab.Screen name="Featured" component={Featured} />
<TopTab.Screen name="Relevant" component={Relevant} />
<TopTab.Screen name="Search" component={Search} />
</TopTab.Navigator>
</>
);
}
function MyBottomTabs({ navigation }) {
return (
<BottomTab.Navigator>
<BottomTab.Screen name="News" component={NewsTopTabs} />
<BottomTab.Screen name="Matches" component={MatchesTopTabs} />
</BottomTab.Navigator>
);
}
//[FEATURED], [RELEVANT], [SEARCH]
export default function App() {
return (
<NavigationContainer>
<MyBottomTabs />
</NavigationContainer>
);
}
//[FEATURED], [RELEVANT], [SEARCH]
const Featured = () => {
const nav = useNavigationState((state) => state);
return (
<View style={styles.screen}>
<Text>Featured</Text>
</View>
);
};
const Relevant = () => {
const nav = useNavigationState((state) => state);
return (
<View style={styles.screen}>
<Text>Relevant</Text>
</View>
);
};
const Search = () => {
const nav = useNavigationState((state) => state);
return (
<View style={styles.screen}>
<Text>Search</Text>
</View>
);
};
const styles = StyleSheet.create({
titleBar: {
height: 50,
width: Math.round(Dimensions.get('window').width),
backgroundColor: 'white',
justifyContent: 'center',
borderBottomColor: "lightgrey",
borderBottomWidth: 1,
paddingLeft: 10,
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
screen:{
flex: 1,
justifyContent: "center",
alignItems: "center"
}
});
Working Example: Expo Snack
I am running a code that displays menu of various dishes where users can press one of the dishes they will be taken to "Dishdetail" screen where read about the dish. The problem is when we get to the point where we click the app is using navigate but the app is throwing some error message that says the "TypeError: Can not read Property 'navigate' of undefined". You can see the code I have it declared in the code below.
MainComponent.js
import React, { Component } from 'react' ;
import Menu from './MenuComponent' ;
import { View, Image, StyleSheet, ScrollView, Text,Platform } from 'react-native'
//import { Platform } from '#unimodules/core';
import Home from './HomeComponent';
import Dishdetail from './DishdetailComponent' ;
import Contact from './ContactComponent' ;
import About from './AboutComponent';
import { Icon } from 'react-native-elements';
import { createStackNavigator, createDrawerNavigator,SafeAreaView,DrawerItems } from 'react-navigation';
//1. ActionCreators import
import { fetchDishes, fetchComments, fetchPromos, fetchLeaders} from '../redux/ActionCreators';
//1.import to connect to redux
import { connect } from 'react-redux';
import {baseUrl } from '../shared/baseUrl';
//2.leaders state from store
const mapStateToProps = state => {
return {
}
}
//2. get the actions creators
const mapDispatchToProps = dispatch => ({
fetchDishes: () => {dispatch(fetchDishes())},
fetchComments:() => {dispatch(fetchComments())},
fetchPromos: () => {dispatch(fetchPromos())},
fetchLeaders: () => {dispatch(fetchLeaders())}
})
//() => <Menu/>
const MenuNavigator = createStackNavigator({
Menu: { screen: () => <Menu/>,
navigationOptions: ({ navigation }) => ({
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={ () => navigation.toggleDrawer()}
/>
})
},
Dishdetail: { screen: () => <Dishdetail/> }
},
{
initialRouteName: 'Menu',
navigationOptions: {
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
}
}
})
//Create stacknavigator for Home Component
const HomeNavigator = createStackNavigator({
Home: { screen: () => <Home/> }
},
{
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
},
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={() => navigation.toggleDrawer()}
/>
})
});
//Create stacknavigator for Contact Component
const ContactNavigator = createStackNavigator({
Contact: { screen: () => <Contact/>}
},
{
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
},
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={() => navigation.toggleDrawer()}
/>
})
});
//Create stacknavigator for About Component
const AboutNavigator = createStackNavigator({
About: { screen: () => <About />}
},
{
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
},
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={() => navigation.toggleDrawer()}
/>
})
});
const CustomDrawerContentComponent = (props) => (
<ScrollView>
<SafeAreaView style= {StyleSheet.container}
forceInset={{ top: 'always', horizontal: 'never'}} >
<View style={styles.drawerHeader} >
<View style={{flex:1}} >
<Image source={require('./images/logo.png')}
style={styles.drawerImage} />
</View>
<View style={{flex: 2}} >
<Text style={styles.drawerHeaderText} >Ristorante Con Fusion</Text>
</View>
</View>
<DrawerItems {...props } />
</SafeAreaView>
</ScrollView>
)
//Create drawerNavigator for all Components
// Modified
const MainNavigator = createDrawerNavigator({
Home:
{
screen: HomeNavigator,
navigationOptions: {
title: 'Home',
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<Icon
name='home'
type='font-awesome'
size={24}
color={tintColor}
/>
)
}
},
About:
{
screen: AboutNavigator,
navigationOptions: {
title: 'About Us',
drawerLabel: 'About Us',
drawerIcon: ({ tintColor }) => (
<Icon
name='info-cirlce'
type='font-awesome'
size={24}
color={tintColor}
/>
)
}
},
Menu:
{
screen: MenuNavigator,
navigationOptions: {
title: 'Menu',
drawerLabel: 'Menu',
drawerIcon: ({ tintColor }) => (
<Icon
name='list'
type='font-awesome'
size={24}
color={tintColor}
/>
)
}
},
Contact:
{
screen: ContactNavigator,
navigationOptions: {
title: 'Contact Us',
drawerLabel: 'Contact Us',
drawerIcon: ({ tintColor }) => (
<Icon
name='address-card'
type='font-awesome'
size={22}
color={tintColor}
/>
)
}
}
},{
drawerBackgroundColor: '#D1C4E9',
contentComponent: CustomDrawerContentComponent
})
class Main extends Component {
//3. Actioncreators to be loaded by componentDidMount()
componentDidMount() {
this.props.fetchDishes();
this.props.fetchComments();
this.props.fetchPromos();
this.props.fetchLeaders();
}
//<Menu />:Display all dishes and when user clicks one of them
//<Dishdetail>: filter the selectedDish and display its detail underneath
render() {
return (
<View style={{flex: 1, paddingTop: Platform.OS === 'ios' ? 0: Expo.Constants.statusBarHeight }}>
<MainNavigator />
</View>
)
}
}
const styles = StyleSheet.create ({
container: {
flex: 1
},
drawerHeader:{
backgroundColor: '#512DA8',
height: 140,
alignItems: 'center',
justifyContent: 'center',
flex: 1,
flexDirection: 'row'
},
drawerHeaderText: {
color: 'white',
fontSize: 24,
fontWeight: 'bold'
},
drawerImage: {
margin: 10,
width: 80,
height: 60
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Main);
MenuComponent.js
import React, { Component } from 'react' ;
import { FlatList } from 'react-native' ;
import { Tile } from 'react-native-elements' ;
//import { DISHES} from '../shared/dishes';
//1.import to connect to redux
import { connect } from 'react-redux';
import { baseUrl } from '../shared/baseUrl';
//2.leaders state from store
const mapStateToProps = state => {
return {
dishes: state.dishes
}
}
//functional component
class Menu extends Component {
constructor(props) {
super(props);
}
//display the Menu navigation at the top
static navigationOptions = {
title : 'Menu'
}
//onPress uses the navigate to pass the dishId to Dishsetail
//to display the dish detail of the selected dish
render() {
//const {navigate} = this.props.navigation ;
const renderMenuItem = ({item, index}) => {
return (
<Tile
key={index}
title={item.name}
caption={item.description}
featured
onPress={() => navigate('Dishdetail', { dishId: item.id })}
imageSrc={{ uri: baseUrl + item.image }}
/>
);
}
//extract the navigation comp passed to be used to pass
//dishId to Dishdetail
//const { navigate } = this.props.navigation ;
return (
<FlatList
data= {this.props.dishes.dishes}
renderItem={renderMenuItem}
keyExtractor={Item => Item.id.toString() }
/>
)
}
}
export default connect(mapStateToProps)(Menu);
DishdetailComponent.js
import React, { Component } from 'react' ;
import { View, Text, ScrollView, FlatList } from 'react-native' ;
import { Card, Icon } from 'react-native-elements' ;
//import { DISHES} from '../shared/dishes';
//import { COMMENTS } from '../shared/comments';
//1.import to connect to redux
import { connect } from 'react-redux';
import {baseUrl } from '../shared/baseUrl';
//2.leaders state from store
const mapStateToProps = state => {
return {
dishes: state.dishes,
comments: state.comments
}
}
//functional component: Display the selectedDish name, image and
//description using <Card> element
function RenderDish(props){
const dish = props.dish;
if (dish != null) {
return (
<Card
featuredTitle={dish.name}
image={{ uri: baseUrl + dish.image }}
>
<Text style={{margin: 10}}>
{dish.description}
</Text>
<Icon
raised
reverse
name={props.favorite ? 'heart' : 'heart-o'}
type='font-awesome'
color='#f50'
onPress={() => props.favorites ? console.log('Already favorite'): props.onPress() }
/>
</Card>
)
}
else {
return (<View></View>)
}
}
// display comments associted with dish
function RenderComments(props) {
// pull the content out from comments array
const comments = props.comments;
const renderCommentsItem = ({ item , index}) => {
return (
<View key={index} style={{ margin: 10}} >
<Text style={{fonSize: 14 }}>{item.comment}</Text>
<Text style={{fontSize: 12}}>{item.rating} Stars</Text>
<Text style={{ fontSize: 12}}>{'--' + item.author + ',' + item.date}</Text>
</View>
)
}
return (
<Card title="Comments">
<FlatList
data={comments}
renderItem={renderCommentsItem}
keyExtractor={item => item.id.toString()}
/>
</Card>
)
}
class Dishdetail extends Component {
constructor(props) {
super(props)
this.state = {
favorites: []
}
}
markFavourite(dishId) {
this.setState({favorites: this.state.favorites.concat(dishId)})
}
//setup the navigation for the current class [Dishdetail]
static navigationOptions = {
title : 'Dish Details'
}
render(){
// pass or extract the dish id through the navigation
const dishId = this.props.navigation.getParam('dishId', '');
return (
<ScrollView>
<RenderDish dish={this.props.dishes.dishes[+dishId]}
favorites={this.state.favorites.some(el => el === dishId)}
onPress={() => this.markFavourite(dishId)}/>
<RenderComments comments={this.props.comments.comments.filter((comment) => comment.dishId === dishId)} />
</ScrollView>
)
}
}
export default connect(mapStateToProps)(Dishdetail);
I am fairly new to Navigation in react-native but i have been able to pick up few things here now i want o add the Hamburger icon to it to do a Proper Menu bar. Since i am fairly new to this, I need help in every way.
My code Looks something like this
import React , {Component} from 'react';
import { View, Text, Image , StyleSheet } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createDrawerNavigator } from 'react-navigation-drawer';
class Home extends React.Component{
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<Image
source={{uri:'http://imageholder.freeasphost.net/home.png'}}
style={[styles.icon, { tintColor: tintColor }]}
/>
),
};
render()
{
return(
<View>
<Text> Welcome to Home screen</Text>
</View>
);
}
}
class Profile extends React.Component{
static navigationOptions = {
drawerLabel: 'Profile',
drawerIcon: ({ tintColor }) => (
<Image
source={{uri:'http://imageholder.freeasphost.net/profile.png'}}
style={[styles.icon, { tintColor: tintColor }]}
/>
),
};
render()
{
return(
<View>
<Text>Welcome to Profile screen</Text>
</View>
);
}
}
class Settings extends React.Component{
static navigationOptions = {
drawerLabel: 'Settings',
drawerIcon: ({ tintColor }) => (
<Image
source={{uri:'http://imageholder.freeasphost.net/settings.png'}}
style={[styles.icon, { tintColor: tintColor }]}
/>
),
};
render()
{
return(
<View>
<Text>Welcome to Settings Screen</Text>
</View>
);
}
}
const MyDrawerNavigator = createDrawerNavigator({
Home:{
screen:Home
},
Settings:{
screen:Settings
},
Profile:{
screen:Profile
},
});
const MyApp = createAppContainer(MyDrawerNavigator);
export default class App extends Component {
render() {
return (
<MyApp/>
);
}
}
const styles = StyleSheet.create({
icon: {
width: 24,
height: 24,
},
});
Like i wanted to use some drawer navigation uri to do it but how to start is the main worry, hence I wanted to know how and what i must do.
I'll always prefer making your own custom component rather than any library.
It's simple, first download icon like this or your icon and create a view box, and then on the image add touchable opacity so that when a user clicks, it will expand
will turn into this
Now steps are like that,
renderUnExpanded=()=>(
<View>
<TouchableOpacity onPress = {this.flipState} >
<Icon />
</TouchableOpacity>
<View>
)
renderExpanded = () =>(
<View>
<TouchableOpacity onPress = {this.flipState} >
<Icon />
</TouchableOpacity>
<ProfileIcon />
<SignoutIcon />
<View>
)
now flipState will be a function to toggle expanded state,
flipState =() => {
this.setState({optionVisible:!this.state.optionVisible})
}
and now in render function , show accordingly to state,
render(){
return(
{this.state.optionVisible?this.renderExpanded():this.renderUnExpanded()}
)
}
hope its clear, otherwise ask any doubts
I want to reload the tabNavigator when the user changse the tab each time. the lifecycle method of react native doesn't get called when user changes the tab. Then how can it be possible to reload tab in TabNavigator :
The below example have two Tabs : 1) Home 2)Events. Now I want to refresh the event Tab when user returns from the home tab.
EXPO LINK : Expo Tab Navigator
Code :
import React, {Component} from 'react';
import {View, StyleSheet, Image, FlatList, ScrollView, Dimensions } from 'react-native';
import { Button, List, ListItem, Card } from 'react-native-elements' // 0.15.0
//import { Constants } from 'expo';
import { TabNavigator, StackNavigator } from 'react-navigation'; // 1.0.0-beta.11
//image screen width and height defs
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
export default class App extends Component {
render() {
//const { navigate } = this.props.navigation;
return (
<TabsNav />
)
}
}
class MyHomeScreen extends Component {
render() {
return (
<View>
<Image
resizeMode="cover"
style={{ width: windowWidth * .85, height: windowHeight * 0.3}}
source={{uri: 'http://www.ajaxlibrary.ca/sites/default/files/media/logo.png?s358127d1501607090'}}
/>
<Button
onPress={() => this.props.navigation.navigate('Notifications')}
title="Go to notifications"
/>
</View>
);
}
}
class AplEvents extends Component {
static navigationOptions = {
tabBarLabel: 'Events List',
tabBarIcon: ({ tintColor }) => (
<Image
source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
};
constructor(props) {
super(props);
this.state = {
data: [],
error: null,
};
}
// when component mounts run the function fetch
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const url = `http://www.ajaxlibrary.ca/?q=calendar-test`;
fetch(url)
.then((res) => res.json())
.then((res) => {
this.setState({
data: [...this.state.data, ...res.nodes],
error: res.error || null,
});
})
.catch(error => {
this.setState( error );
});
};
render() {
const { navigate } = this.props.navigation;
return (
<List containerStyle={{ marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<ListItem
//squareAvatar
title={`${item.node.title}\n${item.node.Program_Location}`}
subtitle={item.node.Next_Session}
avatar={{ uri: item.node.Image }}
containerStyle={{ borderBottomWidth: 0 }}
// save params to pass to detailed events screen
onPress={() => navigate('Details', {title: `${item.node.title}`,
body: `${item.node.Body}`,
date: `${item.node.Date}`,
Next_Session: `${item.node.Next_Session}`,
Program_Location: `${item.node.Program_Location}`,
Nid: `${item.node.Nid}`,
Image: `${item.node.Image}`,
Run_Time: `${item.node.Run_Time}`})}
/>
)}
keyExtractor={item => item.node.Nid}
/>
</List>
);
}
}
class EventDetails extends Component {
static navigationOptions = {
title: 'EventDetails'
};
render() {
const { params } = this.props.navigation.state;
let pic = {
uri: `${params.Image}`
};
//const pic = { params.Image };
return (
<ScrollView>
<Card
title={params.title}
>
<Image
resizeMode="cover"
style={{ width: windowWidth * .85, height: windowHeight * 0.3}}
source={pic}
/>
<Button style={{marginTop: 10}}
icon={{name: 'date-range'}}
backgroundColor='#03A9F4'
fontFamily='Lato'
buttonStyle={{borderRadius: 0, marginLeft: 0, marginRight: 0, marginBottom: 0}}
title='Add to Calendar'
/>
<ListItem
title="Event Description"
subtitle={params.body}
hideChevron='true'
/>
<ListItem
title="Date"
subtitle={`${params.Next_Session}\n Run Time - ${params.Run_Time}`}
hideChevron='true'
/>
<ListItem
title="Location"
subtitle={params.Program_Location}
hideChevron='true'
/>
</Card>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
icon: {
width: 26,
height: 26,
},
});
const EventStack = StackNavigator({
EventList: {
screen: AplEvents,
navigationOptions: {
title: "APL Event Listing",
}
},
Details: {
screen: EventDetails,
},
TabsNav: { screen: MyHomeScreen}
});
const TabsNav = TabNavigator({
Home: {
screen: MyHomeScreen,
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor }) => (
<Image
source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
},
},
EventList: {
screen: EventStack,
navigationOptions: {
tabBarLabel: 'Events',
tabBarIcon: ({ tintColor }) => (
<Image
source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
},
},
}, {
tabBarOptions: {
activeTintColor: '#e91e63',
},
});
React Native Tab Navigation has an option prop as unmountOnBlur set it to true and it will reload the tab screens every time you click on tabs.
<Tab.Screen name={"Profile"} component={ProfileScreen} options={{unmountOnBlur: true}} />
Doc/Ref - RN Bottom tab Navigator docs
.
Update - There is a hook called as useIsFocused in '#react-navigation/native'.
Use this with useEffect to re-render the screen every time it is focused or used .
import { useIsFocused } from '#react-navigation/native';
const isFocused = useIsFocused();
useEffect(() => { yourApiCall(); }, [isFocused])
look at this link. My problem is solving thanks to this.
<Tabs.Navigator
initialRouteName="Home"
tabBar={(props) => (
<TabBar {...props} />
)}>
<Tabs.Screen
name="Home"
component={HomeView}
options={{ unmountOnBlur: true }}
listeners={({ navigation }) => ({
blur: () => navigation.setParams({ screen: undefined }),
})}
/>
</Tabs.Navigator>
https://github.com/react-navigation/react-navigation/issues/6915#issuecomment-692761324
There's many long discussion about this from react-native issue 314, 486, 1335, and finally we got a way to handle this, after Sep 27, 2017, react-navigation version v1.0.0-beta.13:
New Features
Accept a tabBarOnPress param (#1335) - #cooperka
So here we go,
Usage:
const MyTabs = TabNavigator({
...
}, {
tabBarComponent: TabBarBottom /* or TabBarTop */,
tabBarPosition: 'bottom' /* or 'top' */,
navigationOptions: ({ navigation }) => ({
tabBarOnPress: (scene, jumpToIndex) => {
console.log('onPress:', scene.route);
jumpToIndex(scene.index);
},
}),
});
I wasn't able to get this to work, and after checking the React Navigation documentation, found this, which seems to suggest that later versions (I'm using 1.0.0-beta.27) changed the method signature to a single object:
tabBarOnPress Callback to handle tap events; the argument is an object
containing:
the previousScene: { route, index } which is the scene we are leaving
the scene: { route, index } that was tapped
the jumpToIndex method
that can perform the navigation for you
https://reactnavigation.org/docs/en/tab-navigator.html#tabbaronpress
Given that, and the code from beausmith here, I put this together.
navigationOptions: ({ navigation }) => ({
tabBarOnPress: (args) => {
if (args.scene.focused) { // if tab currently focused tab
if (args.scene.route.index !== 0) { // if not on first screen of the StackNavigator in focused tab.
navigation.dispatch(NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: args.scene.route.routes[0].routeName }) // go to first screen of the StackNavigator
]
}))
}
} else {
args.jumpToIndex(args.scene.index) // go to another tab (the default behavior)
}
}
})
Note that you'll need to import NavigationActions from react-navigation for this to work.
Hope this helps somebody :)
I am using react-navigation in RN v 0.46.1 project
I have used customTabs from example directory of react-navigation.
I want to change the color of the tab when active .
I've tried to pass ans use navigationOptions but no success.
Also , Tabs are displayed at top , I want them at bottom.
import React, { Component } from "react";
import { AppRegistry, Button,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View } from "react-native";
import { createNavigator,
createNavigationContainer,
TabRouter,
addNavigationHelpers } from 'react-navigation'
import Chats from './Chats'
import Contacts from './Contacts'
const MyNavScreen = ({ navigation, banner }) => (
<ScrollView>
<Text>banner</Text>
<Button
onPress={() => {
navigation.goBack(null);
}}
title="Go back"
/>
</ScrollView>
);
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen banner="Settings Screen" navigation={navigation} />
);
const CustomTabBar = ({ navigation }) => {
const { routes } = navigation.state;
return (
<View style={styles.tabContainer}>
{routes.map(route => (
<TouchableOpacity
onPress={() => navigation.navigate(route.routeName)}
style={styles.tab}
key={route.routeName}
>
<Text>{route.routeName}</Text>
</TouchableOpacity>
))}
</View>
);
};
const CustomTabView = ({ router, navigation }) => {
const { routes, index } = navigation.state;
const ActiveScreen = router.getComponentForState(navigation.state);
const routeNav = addNavigationHelpers({
...navigation,
state: routes[index],
});
const routeOptions = router.getScreenOptions(routeNav, 'tabBar');
console.log(routeOptions.headerTintColor);
return (
<View style={styles.container}>
<CustomTabBar navigation={navigation} />
<ActiveScreen
navigation={addNavigationHelpers({
...navigation,
state: routes[index],
})}
/>
</View>
);
};
const CustomTabRouter = TabRouter(
{
Friends: {
screen: Chats,
path: '',
},
Status: {
screen: Contacts,
path: 'notifications',
},
Other: {
screen: MySettingsScreen,
path: 'settings',
},
},
{
initialRouteName: 'Friends',
},
);
const CustomTabs = createNavigationContainer(
createNavigator(CustomTabRouter)(CustomTabView)
);
const styles = StyleSheet.create({
container: {
marginTop: Platform.OS === 'ios' ? 20 : 0,
},
tabContainer: {
flexDirection: 'row',
height: 48,
},
tab: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
margin: 4,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 4,
backgroundColor:'white'
},
});
export default CustomTabs;
AppRegistry.registerComponent('awsm', () => CustomTabs);
Compare the active tab's routeName in map and add style like
style={[(this.props.activeRouteName == route.routeName) ? styles.activeTab : styles.tab]}
For styling tabs at bottom you can use ScrollView in parent view and then your tabs so, it will be something like this
<View style={flex:1}>
<ScrollView>
// your page content
</ScrollView>
<Tabs/>
</View>
By using scrollview you will be able to force the tabs at bottom.
Can't you achieve what you want with the default TabNavigator ?
In the docs you can pass a TabBarComponent to the TabNavigator and set tabBarPosition - position of the tab bar, can be 'top' or 'bottom' to bottom so your tabBar will be at the bottom.
If you still want to do all that yourself, I guess :
To align the TabBar on the bottom, you could put { position: 'absolute', bottom: 0 } on the TabBar style
To change the color of your focused Tab, you could do:
const CustomTabBar = ({ navigation }) => {
const { routes, index } = navigation.state;
const isFocused = routes[index].routeName == route.routeName; // Not totally sure about the condition there, but you get the idea?
return (
<View style={styles.tabContainer}>
{routes.map(route => (
<TouchableOpacity
onPress={() => navigation.navigate(route.routeName)}
style={[styles.tab, isFocused ? styles.focusedTab : null]}
key={route.routeName}
>
<Text>{route.routeName}</Text>
</TouchableOpacity>
))}
</View>
);
};
?