Hi am working on my tab navigator, so far so good until I tried to customize the tab navigator by adding icons and customized the colors:
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { Ionicons } from '#expo/vector-icons';
import CategoriesScreen from '../screens/CategoriesScreen';
import CategoryMealsScreen from '../screens/CategoryMealsScreen';
import MealDetailScreen from '../screens/MealDetailScreen';
import FavoritesScreen from '../screens/FavoritesScreen';
import HeaderButton from '../components/HeaderButton';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { CATEGORIES } from '../data/dummy-data';
import Colors from '../constants/colors';
const MealsNav = createStackNavigator();
const MealsNavigator = () => {
return (
<MealsNav.Navigator
mode="modal"
screenOptions={{
headerStyle: {
backgroundColor: Colors.primaryColor,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontSize: 17
}
}}
>
<MealsNav.Screen
name="Categories"
component={CategoriesScreen}
options={{
title: 'Meals Categories'
}}
/>
<MealsNav.Screen
name="CategoryMeals"
component={CategoryMealsScreen}
options={({ route }) => {
const catId = route.params.categoryId;
const selectedCategory = CATEGORIES.find((cat) => cat.id === catId);
return {
title: selectedCategory.title,
};
}}
/>
<MealsNav.Screen
name="MealDetail"
component={MealDetailScreen}
options={{
title: 'Meal Detail',
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='Favorite'
iconName='ios-star'
onPress={() => console.log('Mark as the favorite')}
/>
</HeaderButtons>
),
}}
/>
</MealsNav.Navigator>
);
};
const MealsFavTabNavigator = createBottomTabNavigator();
const MealsTabNav = () => {
return (
<NavigationContainer>
<MealsFavTabNavigator.Navigator>
<MealsFavTabNavigator.Screen
name="Meals"
component={MealsNavigator}
screenOptions={() => ({
tabBarIcon: (tabInfo) => {
return <Ionicons name="ios-restaurant" size={25} color={tabInfo.tintColor} />
}
})}
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'black',
}}
/>
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesScreen}
screenOptions={({ route }) => ({
tabBarIcon: (tabInfo) => {
return <Ionicons name="ios-star" size={25} color={tabInfo.tintColor} />
}
})}
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'black',
}}
/>
</MealsFavTabNavigator.Navigator>
</NavigationContainer>
);
};
export default MealsTabNav;
As you can see here, I tried to add a screenOptions:
const MealsFavTabNavigator = createBottomTabNavigator();
const MealsTabNav = () => {
return (
<NavigationContainer>
<MealsFavTabNavigator.Navigator>
<MealsFavTabNavigator.Screen
name="Meals"
component={MealsNavigator}
screenOptions={() => ({
tabBarIcon: (tabInfo) => {
return <Ionicons name="ios-restaurant" size={25} color={tabInfo.tintColor} />
}
})}
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'black',
}}
/>
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesScreen}
screenOptions={({ route }) => ({
tabBarIcon: (tabInfo) => {
return <Ionicons name="ios-star" size={25} color={tabInfo.tintColor} />
}
})}
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'black',
}}
/>
</MealsFavTabNavigator.Navigator>
</NavigationContainer>
);
};
The icons doesnt work even the colors doesnt work and there are no errors on the console. Any idea what am I doing wrong?
The screenOptions prop is used for navigators not screens.
When using for screens you will have to use 'options' not screenOptions
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesScreen}
options={({ route }) => ({
tabBarIcon: (tabInfo) => {
return <Ionicons name="ios-star" size={25} color={tabInfo.tintColor} />
}
})}
/>
Also the tabBarOptions should be moved to navigator
<MealsFavTabNavigator.Navigator
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'black',
}}>
Related
I am updating my react-native app to use react navigation 6 and I'm trying to figure out how to connect to a screen.
The screen I'm trying to link/navigate to uses a bottomtabnavigator, and looks like this:
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
export const PatientScreen = () => {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator screenOptions={{ headerShown: false }} initialRouteName={'Visits'}>
<Tab.Screen name="Visits" component={VisitsTab}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="street-view" color={color} size={size} />
),
}}
/>
<Tab.Screen name="Chart" component={ChartTab}
options={{
tabBarLabel: 'Charts',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="id-badge" color={color} size={size} />
),
}}
/>
<Tab.Screen name="Goals" component={GoalsTab}
options={{
tabBarLabel: 'Edit Goals',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="trophy" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
}
I am trying to link to the above from within a screen that is part of a different navigator. That screen looks like this:
import { StyleSheet, Text, View, Tab, Button } from 'react-native';
import { PatientScreen } from './PatientScreen';
export const CaseloadScreen = ({navigation}) => {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Caseload</Text>
<Button title="Patient"
onPress={() => navigation.navigate('PatientScreen', { screen: 'Visits' })}
/>
</View>
);
}
When I click on the button above, I get this error:
The action 'NAVIGATE' with payload undefined was not handled by any navigator.
Do you have a screen named 'PatientScreen'?
So clearly I'm missing something, but it's unclear to me what that is. How do I make this PatientScreen which uses a bottomTabNavigator, linkable from the button link I listed above?
My navigator for the Caseload screen looks like this:
import React from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '#react-navigation/drawer';
import { LoginScreen } from '../screens/LoginScreen';
import { CaseloadScreen } from '../screens/CaseloadScreen';
import { WeeklyScreen } from '../screens/WeeklyScreen';
import { ProfileScreen } from '../screens/ProfileScreen';
import { Ionicons, FontAwesome, MaterialCommunityIcons, AntDesign } from '#expo/vector-icons';
import { AvailablePatientScreen } from '../screens/AvailablePatientScreen';
const CustomDrawerContent = (props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} style={{
activeTintColor: {
color: '#fff',
},
}} />
</DrawerContentScrollView>
);
}
const Drawer = createDrawerNavigator();
const DrawerNavigation = () => {
const icons = {
tintColor: '#fff',
size: 20,
}
return (
<Drawer.Navigator initialRouteName={'Caseload'}n
drawerContent={(props) => <CustomDrawerContent {...props} />}
screenOptions={{
labelStyle: {
color: '#fff',
},
inactiveTintColor: {
color: '#fff',
},
drawerStyle: {
backgroundColor: 'rgb(61,77,138)',
width: 240,
activeTintColor: 'rgb(61,77,138)',
activeBackgroundColor: '#fff',
inactiveTintColor: '#fff',
inactiveBackgroundColor: 'rgb(61,77,138)',
},
}}
>
<Drawer.Screen name="Caseload" component={CaseloadScreen} options={{
drawerIcon: () => (<Ionicons name="ios-home" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="Weekly Summary" component={WeeklyScreen} options={{
drawerIcon: () => (<FontAwesome name="bar-chart" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="Available RiverKids" component={AvailablePatientScreen} options={{
drawerIcon: () => (<FontAwesome name="child" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="My Profile" component={ProfileScreen} options={{
drawerIcon: () => (<AntDesign name="profile" size={icons.size} color={icons.tintColor} />)
}} />
{/* <Drawer.Screen name="Patient" component={PatientScreen} options={{
drawerIcon: () => (<FontAwesome name="bar-chart" size={icons.size} color={icons.tintColor} />)
}} /> */}
<Drawer.Screen name="Login" component={LoginScreen} options={{ title: 'Sign Out',
drawerIcon: () => (<MaterialCommunityIcons name="logout" size={icons.size} color={icons.tintColor} />)
}} />
</Drawer.Navigator>
);
}
export const Navigator = () => {
return (
<NavigationContainer>
<DrawerNavigation />
</NavigationContainer>
);
}
In your drawer navigator there is no screen defined with the name 'PatientScreen';
I can see a commented screen in your drawer navigator which has a name Patient and the component is PatientScreen. If you wish to navigate the Patient Screen from the drawer, do uncomment that code and then do the below
import { StyleSheet, Text, View, Tab, Button } from 'react-native';
export const CaseloadScreen = ({navigation}) => {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Caseload</Text>
<Button title="Patient"
onPress={() => navigation.navigate('Patient', { screen: 'Visits' })}
/>
</View>
);
}
Or else if you wish to navigate the PatientScreen only from the Caseload Screen, then create a Stack Navigator with the caseload and patient screen and then in the drawer navigator use that stack navigator in place of caseload screen
I am getting a "Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined" error in my react native app after doing some refactoring. I am unclear what's causing the issue, but appears to be related to how I am importing/exporting something into the file below.
My root App() code looks like this:
import React, { useState, useEffect } from 'react';
import Navigator from './navigation/navigator';
import { LoginScreen } from './screens/LoginScreen';
export default function App() {
const [isLoggedIn, setIsloggedIn] = useState(false);
useEffect(() => {
setTimeout(() => {
setIsloggedIn(true);
}, 3000);
}, []);
return (
isLoggedIn ? (
<Navigator />
) : (
<LoginScreen />
)
);
}
And the navigator file I am importing into the above file looks like this:
import React from 'react';
import { StyleSheet, View, Feather } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '#react-navigation/drawer';
import { LoginScreen } from '../screens/LoginScreen';
import { CaseloadScreen } from '../screens/CaseloadScreen';
import { PatientScreen } from '../screens/PatientScreen';
import { WeeklyScreen } from '../screens/WeeklyScreen';
import { ProfileScreen } from '../screens/ProfileScreen';
import { Ionicons, FontAwesome, MaterialCommunityIcons, AntDesign } from '#expo/vector-icons';
import { AvailablePatientScreen } from '../screens/AvailablePatientScreen';
const CustomDrawerContent = (props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} style={{
activeTintColor: {
color: '#fff',
},
}} />
</DrawerContentScrollView>
);
}
const Drawer = createDrawerNavigator();
const DrawerNavigation = ({ navigation }) => {
const icons = {
tintColor: '#fff',
size: 20,
}
return (
<Drawer.Navigator initialRouteName={'Caseload'}
drawerContent={(props) => <CustomDrawerContent {...props} />}
options={{
headerLeft: (
<View>
<Feather name='menu' size={24}
onPress={() => navigation.toggleDrawer()}
color={'blue'} style={{}} />
</View>
),
}}
screenOptions={{
labelStyle: {
color: '#fff',
},
inactiveTintColor: {
color: '#fff',
},
drawerStyle: {
backgroundColor: 'rgb(61,77,138)',
width: 240,
activeTintColor: 'rgb(61,77,138)',
activeBackgroundColor: '#fff',
inactiveTintColor: '#fff',
inactiveBackgroundColor: 'rgb(61,77,138)',
},
}}
>
<Drawer.Screen name="Caseload" component={CaseloadScreen} options={{
drawerIcon: () => (<Ionicons name="ios-home" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="Weekly Summary" component={WeeklyScreen} options={{
drawerIcon: () => (<FontAwesome name="bar-chart" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="Available RiverKids" component={AvailablePatientScreen} options={{
drawerIcon: () => (<FontAwesome name="child" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="My Profile" component={ProfileScreen} options={{
drawerIcon: () => (<AntDesign name="profile" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="The Guys" component={TheGuysScreen} options={{
drawerIcon: () => (<Ionicons name="ios-chatbubbles" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="Patient" component={PatientScreen} options={{
drawerItemStyle: { display: 'none' },
headerShown: false,
}} />
<Drawer.Screen name="Login" component={LoginScreen} options={{ title: 'Sign Out',
drawerIcon: () => (<MaterialCommunityIcons name="logout" size={icons.size} color={icons.tintColor} />)
}} />
</Drawer.Navigator>
);
}
export default function Navigator() {
return (
<NavigationContainer>
<DrawerNavigation />
</NavigationContainer>
);
}
The one other import in the root is for LoginScreen, which looks like this:
import {
TouchableWithoutFeedback,
Text,
TextInput,
KeyboardAvoidingView,
Keyboard,
View,
Image,
Button,
} from 'react-native';
import styles from '../styles';
import { GradientButton } from '../components/GradientButton';
export const LoginScreen = (props) => {
console.log('props: ', props);
return (
<TouchableWithoutFeedback
onPress={Keyboard.dismiss}
>
<View style={styles.login.container}>
// Other code
</View>
</TouchableWithoutFeedback>
);
}
I am trying to navigate from SplashScreen to another screen after 5 second and I get this error:
Code from SplashScreen:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View,Alert, ImageBackground,Image,AsyncStorage,ActivityIndicator} from 'react-native';
import { StackNavigator } from 'react-navigation';
export default class App extends Component<Props> {
componentDidMount () {
setTimeout(() => {
// this._retrieveData();
this.props.navigation.replace("Journeys");
}, 5000)
}
render() {
return (
<ImageBackground
source={require('../../assets/rsz_blue_bg.png')}
style = {{flex: 1, height: '100%', width: '100%', resizeMode : 'stretch'}}>
<Image
source={require('../../assets/logo_white.png')}
style = {{ width: '100%', height:'70%', marginTop: 100 }}
/>
</ImageBackground>
);
}
}
Code from App.js:
import React, { useContext, useEffect } from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import Icon from 'react-native-vector-icons/Ionicons';
//I am doing the imports here but I am cutting down the code to be able to post :)
const AuthStack = createStackNavigator()
const AuthStackScreen = () => (
<AuthStack.Navigator screenOptions={{headerShown: false}}>
<AuthStack.Screen name="SignIn" component={SignInScreen} />
<AuthStack.Screen name="SignUp" component={SignUpScreen} />
</AuthStack.Navigator>
)
const FirstStack = createStackNavigator()
const FirstStackScreen = ({navigation}) => (
<FirstStack.Navigator screenOptions={{
headerStyle: {
backgroundColor: '#009387'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
// alignSelf: 'center',
}
}}>
<FirstStack.Screen
name="Journeys"
component={TrackCreateScreen}
options={{
headerLeft: () => (
<Icon.Button
name="ios-menu"
size={25}
backgroundColor="#009387"
onPress={() => {navigation.openDrawer()}}></Icon.Button>
)
}}
/>
</FirstStack.Navigator>
)
const TrackListStack = createStackNavigator()
const TrackListScreens = ({navigation}) => (
<TrackListStack.Navigator screenOptions={{
headerStyle: {
backgroundColor: '#009387'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold'
}
}}>
<TrackListStack.Screen
name="History"
component={TrackListScreen}
options={{
headerLeft: () => (
<Icon.Button
name="ios-menu"
size={25}
backgroundColor="#009387"
onPress={() => {navigation.openDrawer()}}></Icon.Button>
)
}}
/>
<TrackListStack.Screen name="Journey Details" component={TrackDetailScreen} />
</TrackListStack.Navigator>
)
const AccountStack = createStackNavigator()
const AccountScreens = ({navigation}) => (
<AccountStack.Navigator screenOptions={{
headerStyle: {
backgroundColor: '#009387'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold'
}
}}>
<AccountStack.Screen
name="Account"
component={AccountScreen}
options={{
headerLeft: () => (
<Icon.Button
name="ios-menu"
size={25}
backgroundColor="#009387"
onPress={() => {navigation.openDrawer()}}></Icon.Button>
)
}}
/>
</AccountStack.Navigator>
)
const AppStack = createDrawerNavigator()
const AppStackScreen = ({navigation}) => (
<AppStack.Navigator drawerContent={props => <DrawerContent {...props}/>}>
<AppStack.Screen name="Journey" component={FirstStackScreen} />
<AppStack.Screen name="History" component={TrackListScreens} />
<AppStack.Screen name="Account" component={AccountScreens} />
</AppStack.Navigator>
)
const App = () => {
const { state } = useContext(AuthContext)
if(state.isLoading) {
return <LoadingScreen />
}
return (
<NavigationContainer>
<SplashScreen/>
</NavigationContainer>
)
}
export default () => (
<AuthProvider>
<LocationProvider>
<TrackProvider>
<App />
</TrackProvider>
</LocationProvider>
</AuthProvider>
)
Or if you have a better option to do this redirection it's ok anyway.
I tried various methods and for sure I am doing something wrong.
Please help.
this is not accessible in setTimeout.
componentDidMount () {
let self = this;
setTimeout(() => {
// this._retrieveData();
self.props.navigation.replace("Journeys");
}, 5000)
}
I was trying to use my new created navigator stack on my bottom navigator tabs item so that I can use it instead of a regular screen.
So far I created the new stack navigator:
const FavoritesNav = () => {
return(
<FavoritesStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: Colors.primaryColor,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontSize: 17
}
}}>
<FavoritesStack.screen
name="Favorite"
component={FavoritesScreen}
/>
<FavoritesStack.screen
name="MealDetail"
component={MealDetailScreen}
/>
</FavoritesStack.Navigator>
);
};
And then, I tried to pass this on one of the item of my bottom navigator:
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesNav}
options={{
tabBarIcon: ({ focused, color, size }) => (
<Ionicons name="ios-star" size={25} color={focused ? "tomato" : "black"} />
)
}}
/>
This throws me an error: A navigator can only contain 'Screen' components as its diection children (found [object, object])
How can I pass my newly created stack to the bottom tab nav?
PS. Here's my complete code:
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { Ionicons } from '#expo/vector-icons';
import { Platform } from 'react-native';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import CategoriesScreen from '../screens/CategoriesScreen';
import CategoryMealsScreen from '../screens/CategoryMealsScreen';
import MealDetailScreen from '../screens/MealDetailScreen';
import FavoritesScreen from '../screens/FavoritesScreen';
import HeaderButton from '../components/HeaderButton';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { CATEGORIES } from '../data/dummy-data';
import Colors from '../constants/colors';
const MealsNav = createStackNavigator();
const MealsNavigator = () => {
return (
<MealsNav.Navigator
mode="modal"
screenOptions={{
headerStyle: {
backgroundColor: Colors.primaryColor,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontSize: 17
}
}}
>
<MealsNav.Screen
name="Categories"
component={CategoriesScreen}
options={{
title: 'Meals Categories'
}}
/>
<MealsNav.Screen
name="CategoryMeals"
component={CategoryMealsScreen}
options={({ route }) => {
const catId = route.params.categoryId;
const selectedCategory = CATEGORIES.find((cat) => cat.id === catId);
return {
title: selectedCategory.title,
};
}}
/>
<MealsNav.Screen
name="MealDetail"
component={MealDetailScreen}
options={{
title: 'Meal Detail',
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='Favorite'
iconName='ios-star'
onPress={() => console.log('Mark as the favorite')}
/>
</HeaderButtons>
),
}}
/>
</MealsNav.Navigator>
);
};
const MealsFavTabNavigator =
Platform.OS === 'android'
? createMaterialBottomTabNavigator()
: createBottomTabNavigator();
const getNavigationOptions = () => {
if (Platform.OS === 'ios') {
// Props for the ios navigator
return {
labeled: false,
initialRouteName: 'Meals',
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'black',
},
};
}
// Props for android
return {
initialRouteName: 'Favorites',
activeColor: 'tomato',
inactiveColor: 'black',
barStyle: { backgroundColor: Colors.primaryColor },
shifting: true
};
};
const MealsTabNav = () => {
return (
<NavigationContainer>
<MealsFavTabNavigator.Navigator {...getNavigationOptions()} >
<MealsFavTabNavigator.Screen
name="Meals"
component={MealsNavigator}
options={{
tabBarIcon: ({ focused, color, size }) => (
<Ionicons name="ios-restaurant" size={25} color={focused ? "tomato" : "black"} />
)
}}
/>
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesNav}
options={{
tabBarIcon: ({ focused, color, size }) => (
<Ionicons name="ios-star" size={25} color={focused ? "tomato" : "black"} />
)
}}
/>
</MealsFavTabNavigator.Navigator>
</NavigationContainer>
);
};
const FavoritesStack = createStackNavigator();
const FavoritesNav = () => {
return(
<FavoritesStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: Colors.primaryColor,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontSize: 17
}
}}>
<FavoritesStack.screen
name="Favorite"
component={FavoritesScreen}
/>
<FavoritesStack.screen
name="MealDetail"
component={MealDetailScreen}
/>
</FavoritesStack.Navigator>
);
};
export default MealsTabNav;
Thanks for those who will help.
Guess you are importing FavoritesScreen but using FavoriteScreen in code.
import FavoritesScreen from '../screens/FavoritesScreen';
const FavoritesNav = () => {
<NavigationContainer>
<FavoritesStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: Colors.primaryColor,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontSize: 17
}
}}>
<FavoritesStack.screen
name="Favorite"
component={FavoritesScreen}
/>
<FavoritesStack.screen
name="MealDetail"
component={MealDetailScreen}
/>
</FavoritesStack.Navigator>
</NavigationContainer>
};
On my navigation tab, I want to change the color of the label + the color of the icon when its active, so what I did is created an if and else statement:
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesScreen}
options={({ route }) => ({
tabBarIcon: (tabInfo) => {
if (route.name === 'Favorites'){
return <Ionicons name="ios-star" size={25} color='tomato'/>
} else {
return <Ionicons name="ios-star" size={25} color='black' />
}
}
})}
My label color is also fixed above the Navigator level:
<MealsFavTabNavigator.Navigator
tabBarOptions={{
activeTintColor: Colors.primaryColor,
inactiveTintColor: 'black',
}}>
Here's my full code:
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { Ionicons } from '#expo/vector-icons';
import CategoriesScreen from '../screens/CategoriesScreen';
import CategoryMealsScreen from '../screens/CategoryMealsScreen';
import MealDetailScreen from '../screens/MealDetailScreen';
import FavoritesScreen from '../screens/FavoritesScreen';
import HeaderButton from '../components/HeaderButton';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { CATEGORIES } from '../data/dummy-data';
import Colors from '../constants/colors';
const MealsNav = createStackNavigator();
const MealsNavigator = () => {
return (
<MealsNav.Navigator
mode="modal"
screenOptions={{
headerStyle: {
backgroundColor: Colors.primaryColor,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontSize: 17
}
}}
>
<MealsNav.Screen
name="Categories"
component={CategoriesScreen}
options={{
title: 'Meals Categories'
}}
/>
<MealsNav.Screen
name="CategoryMeals"
component={CategoryMealsScreen}
options={({ route }) => {
const catId = route.params.categoryId;
const selectedCategory = CATEGORIES.find((cat) => cat.id === catId);
return {
title: selectedCategory.title,
};
}}
/>
<MealsNav.Screen
name="MealDetail"
component={MealDetailScreen}
options={{
title: 'Meal Detail',
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='Favorite'
iconName='ios-star'
onPress={() => console.log('Mark as the favorite')}
/>
</HeaderButtons>
),
}}
/>
</MealsNav.Navigator>
);
};
const MealsFavTabNavigator = createBottomTabNavigator();
const MealsTabNav = () => {
return (
<NavigationContainer>
<MealsFavTabNavigator.Navigator
tabBarOptions={{
activeTintColor: Colors.primaryColor,
inactiveTintColor: 'black',
}}>
<MealsFavTabNavigator.Screen
name="Meals"
component={MealsNavigator}
options={({ route }) => ({
tabBarIcon: ({ color }) => {
if(route.name === 'Meals'){
color = 'tomato'
} else if (route.name === 'Favorites') {
color = 'black'
}
return <Ionicons name="ios-restaurant" size={25} color={color}/>
}
})}
/>
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesScreen}
options={({ route }) => ({
tabBarIcon: (tabInfo) => {
if (route.name === 'Favorites'){
return <Ionicons name="ios-star" size={25} color='tomato'/>
} else {
return <Ionicons name="ios-star" size={25} color='black' />
}
}
})}
/>
</MealsFavTabNavigator.Navigator>
</NavigationContainer>
);
};
export default MealsTabNav;
How can I change the color of the label and color of the iconicons when its active? My solution doesnt work.
By default there are parameters for colors in tabbar icon and tabbar label and these are set to the active tint color and inactive tint color.
But if you have a requirement to override this you can do the following
<Tab.Screen
name="Feed"
component={Feed}
options={{
tabBarLabel:({ focused,color })=>(<Text style={{color:focused?"red":"aqua"}}>1232</Text>),
tabBarIcon: ({ focused,color, size }) => (
<MaterialCommunityIcons name="home" color={focused?"green":"blue"} size={size} />
),
}}
/>
References on the props
tabBarLabel can be a text or a react node, and you get the focused and the color as arguments, The color will be the color you set as activetintcolor or inactivetintcolor.
focused is a boolean on whether the tab is focused or not.
Same arguments are passed to the tabBarIcon only difference is the size which is the size of the icon.
If you see the code above, I have given custom colors based on focused without using the color that is passed. You can do this as per your requirement.
https://stackoverflow.com/a/63033684/17735463 - This is a valid answer but mine works fine too (react-navigation-v5)
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused }) => {
let iconName;
let size=25;
let color = focused ? 'black' : 'gray';
if (route.name === 'HomeScreen') {
iconName = 'ios-home';
return <Ionicons name={iconName} size={size} color={color} />;
} else if (route.name === 'FavoritesScreen') {
iconName = 'star';
return <AntDesign name={iconName} size={size} color={color} />;
}
tabBarLabel: ({ focused }) => {
let titleStyle = {
fontSize: 12,
fontWeight: focused ? 'bold' : '500',
color: focused ? 'black' : 'gray',
};
if (route.name === 'HomeScreen') {
return <Text style={titleStyle}>Home</Text>;
} else if (route.name === 'FavoritesScreen') {
return <Text style={titleStyle}>Favorites</Text>;
}
},
})}>
<Tab.Screen name='Home' component={HomeScreen}/>
<Tab.Screen name='Favorites' component={FavoritesScreen}/>
</Tab.Navigator>