How to center tabs in MaterialTopTabNavigator in ReactNative - react-native

I added tabStyle: { width: "auto" } to fit the tabs of MaterialTopTabNavigator to the width of the text, but by adding this, the tabs are moved to the left side as shown in the image below.
Tabs are too far to the left.
The answer to this question says to remove tabStyle, but if I remove tabStyle, all tabs will have the same width.
I thought about using my own component in the tabBar, but I gave up because I couldn't reproduce the animation when moving the tab.
I thought about using paddingHorizontal to force it to be centered, but I decided against it because it might not be centered if the font size is changed in the OS.
If you know more about this, please let me know how to solve it.
The design I want to implement (edited in Paint)
import { View, Text, StyleSheet, Button, SafeAreaView } from "react-native";
import React, { useRef } from "react";
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
const Tab = createMaterialTopTabNavigator();
const Page = () => {
return (
<Tab.Navigator
tabBarOptions={{
labelStyle: {
fontSize: 14,
fontWeight: "bold",
},
activeTintColor: "#ffffff",
inactiveTintColor: "#000000",
pressOpacity: 1,
indicatorStyle: {
backgroundColor: "black",
height: 30,
borderRadius: 30,
top: 9,
},
tabStyle: {
width: "auto",
},
}}
>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Message" component={Message} />
<Tab.Screen name="Store" component={Store} />
</Tab.Navigator>
);
};
export default Page;

I think this should definitely work. If not, let me know.
import { View, Text, StyleSheet, Button, SafeAreaView } from "react-native";
import React, { useRef } from "react";
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
const Tab = createMaterialTopTabNavigator();
const Page = () => {
return (
<Tab.Navigator
tabBarOptions={{
labelStyle: {
fontSize: 14,
fontWeight: "bold",
},
activeTintColor: "#ffffff",
inactiveTintColor: "#000000",
pressOpacity: 1,
indicatorStyle: {
backgroundColor: "black",
height: 30,
borderRadius: 30,
top: 9,
},
tabStyle: {
width: "auto",
},
}}
>
<View style={{flexDirection:"row", justifyContent:"center"}}>
<View>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Message" component={Message} />
<Tab.Screen name="Store" component={Store} />
</View>
</View>
// If the above does not work than use the below one and comment the above part
// <View style={{flexDirection:"row", justifyContent:"center"}}>
// <Tab.Screen name="Home" component={Home} />
// <Tab.Screen name="Message" component={Message} />
// <Tab.Screen name="Store" component={Store} />
// </View>
</Tab.Navigator>
);
};

You can add tabBarContentContainerStyle attribute below, it works well for me:
<Tab.Navigator
initialRouteName="Attention"
screenOptions={{
lazy: true,
tabBarPressOpacity: 1,
tabBarPressColor: 'rgba(0,0,0,0)',
tabBarInactiveTintColor: Style.unActiveText,
tabBarActiveTintColor: Style.mainColor,
tabBarContentContainerStyle: {
alignItems: 'center',
justifyContent: 'center',
},
tabBarIndicatorStyle: {
display: 'none',
},
tabBarItemStyle: {
width: 70,
paddingHorizontal: 0,
position: 'relative',
padding: 0,
height: 45,
},
tabBarLabelStyle: {
fontSize: 15,
},
tabBarStyle: {
width: 'auto',
height: 45,
borderBottomColor: 'red',
backgroundColor: '#fff',
},
}}>
</Tab.Navigator>

Just apply those styles to screenOptions parameter in your navigator and you're done:
tabBarStyle: {
alignSelf: "center",
flexDirection: "row",
},
tabBarItemStyle: {
width: "auto",
}

Related

How to add an indicator under the active bottom tab?

I need to add an indicator for the active tab I tried to add a borderBottom with tabStyle but we can't check focused with that.
Using react-navigation v5 and createBottomTabNavigator for bottom tabs.
Here's my code:
<BottomTab.Navigator
tabBarOptions={{
activeTintColor: colors.brown,
labelPosition: 'below-icon',
}}>
<BottomTab.Screen
name="Home"
component={HomeTabNav}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({focused}) => {
return focused ? (
<HomeSelectedIcon height={ms(24)} width={ms(24)} />
) : (
<HomeIcon height={ms(24)} width={ms(24)} />
);
},
}}
/>
...
</BottomTab.Navigator>
);
};
Thanks in advance!
I figured it out myself by making a custom tabbar icon if someone needs to achieve this using the bottom-tab bar only.
Here's the code.
<BottomTab.Navigator
tabBarOptions={{
activeTintColor: colors.brown,
showLabel: false,
tabStyle: styles.tabStyle,
style: styles.tabContainerStyle,
}}>
<BottomTab.Screen
name="Home"
component={HomeTabNav}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({focused}) => {
return focused ? (
<View style={styles.labelFocusedContainer}>
<HomeSelectedIcon height={24} width={24} />
<Text style={styles.labelFocusedStyle}>Home</Text>
</View>
) : (
<View style={styles.labelContainer}>
<HomeIcon height={24} width={24} />
<Text style={styles.labelStyle}>Home</Text>
</View>
);
},
}}
/>
...
</BottomTab.Navigator>
const styles = StyleSheet.create({
labelContainer: {
alignItems: 'center',
width: '100%',
},
labelFocusedContainer: {
alignItems: 'center',
width: '100%',
borderBottomWidth: 3,
borderBottomColor: colors.brown,
},
labelFocusedStyle: {
textAlign: 'center',
marginVertical: 8,
color: colors.brown,
backgroundColor: 'transparent',
fontSize: 10,
},
labelStyle: {
textAlign: 'center',
marginVertical: 8,
color: colors.veryDarkgray,
backgroundColor: 'transparent',
fontSize: 10,
},
});
But the best and easy way to do this is by using createMaterialTopTabNavigator and using these props.
tabBarPosition="bottom"
tabBarOptions={{
showIcon: true,
pressOpacity: 1,
iconStyle: styles.iconStyle,
showLabel: true,
activeTintColor: colors.brown,
indicatorStyle: {
borderWidth: 2,
borderColor: colors.brown,
},
This does not seem to be possible / easily achievable with bottom-tabs, but you could use the material version - #react-navigation/material-top-tabs and configure it to match your needs, specifically using tabBarPosition="bottom" and tabBarOptions={{ indicatorStyle: { backgroundColor } }}.
You can check more options in the docs: https://reactnavigation.org/docs/material-top-tab-navigator/#tabbaroptions
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
const Tabs = createMaterialTopTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tabs.Navigator tabBarPosition="bottom" tabBarOptions={{ indicatorStyle: { backgroundColor: 'red' } }}>
<Tabs.Screen name="screen 1" component={View} />
<Tabs.Screen name="screen 2" component={View} />
</Tabs.Navigator>
</NavigationContainer>
);
}
The best answer would be to use the tabBarButton prop to override and add your own custom styles to the container of the tab button.
https://reactnavigation.org/docs/bottom-tab-navigator#tabbarbutton
const CustomTabButton = (props) => (
<Pressable
{...props}
style={
props.accessibilityState.selected
? [props.style, styles.activeTab]
: props.style
}
/>
)
styles.activeTab is the custom style you want to add, be careful to spread the props.style to get the default styles from the library like width, padding, height etc
props.accessibilityState.selected will add styles according to condition if you want styles for all the tabs you can remove the condition.
Inside screeenOptions prop on navigator or the option props of each screen.
tabBarButton: CustomTabButton
Using material top tab is not a good solution because it does not support well with a keyboard. But bottom tabs do work well with the keyboard.

tab bar icons not perfectly centered when screen changes

I have a issue with my costume tab bar and that is when I select other screens icons lose their position a little bit and shift to for example right. for better understanding consider these two images:
you can see this compass icon is not centered perfectly:
but when I tap on screen this become perfectly centered:
here's my styles on custom bottom tab bar :
const TabComponent = ({label, accessibilityState, onPress}) => {
const focused = accessibilityState.selected;
const icon = focused ? ICONS[`${label}Active`] : ICONS[label]
return (
<TouchableWithoutFeedback onPress={onPress}>
<View focused={focused} style={[styles.container, focused ? styles.focused : null]}>
<Image style={styles.icon} source={icon} />
</View>
</TouchableWithoutFeedback>
)
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 20
},
focused: {
backgroundColor: '#3170FF',
borderRadius: 25,
width: 46,
height: 75,
position: 'relative',
bottom: 20
},
icon: {
width: 24,
height: 24,
}
})
and below is my styles on bottom tab itself:
<Tab.Navigator tabBarOptions={{
style: {
borderTopLeftRadius: 23,
borderTopRightRadius: 23,
height: 64,
alignItems: 'center',
}
}} >
<Tab.Screen name="Home" component={Home} options={{
tabBarButton: (props) => <TabComponent label='home' {...props} />,
}}/>
...
how can I fix this issue? any help would be great.

change active tab background color in react navigation material top tabs

How can I change the background color of the active tab while using material-top-tabs from React Navigation?
Here's what things look like right now:
Screenshot 1
Screenshot 2
Here's my code:
import React from 'react'
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
import CrurrentOrders from './CrurrentOrders';
import PastOrders from './PastOrders';
const Tab = createMaterialTopTabNavigator();
const OrdersTabs = () => {
return (
<Tab.Navigator
initialRouteName='CrurrentOrders'
backBehavior='initialRoute'
tabBarPosition='top'
swipeEnabled={true}
swipeVelocityImpact={0.2}
springVelocityScale={0}
sceneContainerStyle={{ backgroundColor: '#d1dfff', margin: 10, borderRadius: 20 }}
style={{ backgroundColor: '#ffffff' }}
tabBarOptions={{
activeTintColor: '#ffffff',
inactiveTintColor: '#ffffff',
showIcon: true,
pressColor: '#856',
scrollEnabled: false,
tabStyle: { backgroundColor: '#36A7E7', borderRadius: 30, margin: 12, justifyContent: 'center', alignContent: 'center' },
indicatorStyle: { backgroundColor: '#987', opacity: 0.05 },
style: { backgroundColor: '#ffffff', borderRadius: 30, margin: 24, height: 72, width: '90%' },
labelStyle: { fontSize: 14 },
}}
>
<Tab.Screen
name="CrurrentOrders"
component={CrurrentOrders}
options={{
title: 'Awsome app',
tabBarTestID: 'werwer',
}}
/>
<Tab.Screen
name="PastOrders"
component={PastOrders}
/>
</Tab.Navigator>
)
}
export default OrdersTabs
I had this exact challenge and was able to solve it by specifying the background color and full height in the indicatorStyle option:
import * as React from 'react';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
import HomeScreen from './HomeScreen';
import AboutScreen from './AboutScreen';
import ContactScreen from './ContactScreen';
const Tab = createMaterialTopTabNavigator();
export default function TopTabs() {
const tabBarOptions = {
activeTintColor: 'white',
inactiveTintColor: 'black',
indicatorStyle: { backgroundColor: 'red', height: '100%' },
pressOpacity: 1,
}
return (
<Tab.Navigator tabBarOptions={tabBarOptions}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="About" component={AboutScreen} />
<Tab.Screen name="Contact" component={ContactScreen} />
</Tab.Navigator>
);
}
Like Defined here material-top-tab-navigator/ changed the layer color (text color) of the active tab
For background change, you can do something like
function MyTabBar({ state, descriptors, navigation, position }) {
return (
<View style={{ flexDirection: 'row' }}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const inputRange = state.routes.map((_, i) => i);
const bgColor = isFocused ? "blue" : "black"; <!-- Here is bg color -->
return (
<TouchableOpacity
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
style={{ flex: 1 }}
>
<View style={{backgroundColor: bgColor}}>
<Animated.Text style={{ opacity }}>
{label}
</Animated.Text>
</View>
</TouchableOpacity>
);
})}
</View>
);
}
Thank you for the link , the hack was in indicatorStyle with activeTintColor
tabBarOptions={{
activeTintColor: '#ffffff',
inactiveTintColor: '#36A7E7',
showIcon: true,
pressColor: '#9BC9E2',
scrollEnabled: false,
tabStyle: {
borderRadius: 30,
margin: 12,
justifyContent: 'center',
alignContent: 'center'
},
indicatorStyle: {
backgroundColor: '#36A7E7',
height: '80%',
borderRadius: 30,
marginBottom: 8,
marginLeft: 12,
width: '45%'
},
style: {
backgroundColor: '#ffffff',
borderRadius: 36,
margin: 24,
height: 76,
width: '90%'
},
labelStyle: { fontSize: 14 },
}}
enter image description here

How to horizontally center TopTabNavigator in React Native?

I've been struggling to apply the proper styling so that my Top Tab Navigator is horizontally centered on the screen. I've tried applying AlignItems: center to the different style props but that does not seem to work. Any tips?
Here is the documentation I have been following: https://reactnavigation.org/docs/material-top-tab-navigator/
import React from "react";
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
import Creators from "../../screens/Creators/Creators";
import Feed from "../../screens/Feed/Feed";
import Profile from "../../screens/Profile/Profile";
const Tab = createMaterialTopTabNavigator();
function TabNav() {
return (
<Tab.Navigator
tabBarOptions={{
labelStyle: {
fontSize: 12,
color: "white",
},
tabStyle: {
width: 100,
height: 40,
marginTop: 50,
},
indicatorStyle: {
backgroundColor: "white",
},
style: {
backgroundColor: "#03182d",
},
}}
>
<Tab.Screen name="Creators" component={Creators} />
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Profile" component={Profile} />
</Tab.Navigator>
);
}
export default TabNav;
remove tabStyle and it will work perfectly like this
<Tab.Navigator
tabBarOptions={{
labelStyle: {
fontSize: 12,
color: "white",
},
//remove this
//tabStyle: {
// width: 100,
// height: 40,
// marginTop: 50,
},
indicatorStyle: {
backgroundColor: "white",
},
style: {
backgroundColor: "#03182d",
},
}}
>
<Tab.Screen name="Creators" component={Creators} />
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Profile" component={Profile} />
</Tab.Navigator>
or remove only width as it is smudging your tabs

Lost with icons

I am trying to add a floating action button with multiple options. When I try to change the icon for the actionbuton item the icon is not found and a question mark is displayed.
I imported the Ionicons so I am checking in that list what buttons to add. I need a plus with outline which is this one here : add-circle-outline
But when I use that instead of md-create it is not found, which is strange since md-create is found and thus displayed . When I search for md-create in ionicons it is not found, so it must come from another library.
I think it is obvious that I am lost here. I read about extra installatin steps for icons as a custom font, but I am guessing this is not required, since md-create is working properly.
This is my page:
/* eslint-disable prettier/prettier */
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import Scan from './Scan';
import Kowops from './Kowops';
import Wallet from './Wallet';
import ActionButton from 'react-native-action-button';
import Icon from 'react-native-vector-icons/Ionicons';
export class Main extends Component {
render() {
return (
<View style={styles.container}>
<View style={{alignItems: 'center'}}>
<Text style={styles.plainText} onPress={() => this.props.navigation.navigate('Register')}>
This is the main page, return to registration
</Text>
<View style={{height:5}}></View>
</View>
<View style={styles.FABContainer}>
<ActionButton buttonColor="#c5e1a5">
<ActionButton.Item
style={styles.actionButtonItem}
buttonColor= '#c5e1a5'
title="Add a thing"
onPress={() => console.log("notes tapped!")}
>
<Icon name="md-create" style={styles.actionButtonIcon} />
</ActionButton.Item>
</ActionButton>
</View>
</View>
)
}
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
tabBarOptions={{
activeTintColor: 'black',
inactiveBackgroundColor: '#c5e1a5',
inactiveTintColor: 'gray',
labelStyle: {fontSize: 14},
style:
{
backgroundColor: '#c5e1a5',
borderTopColor: 'transparent',
padding: 0,
activeTabStyle: {
fontWeight: 'bold',
}
},
tabStyle: {
borderRightColor: 'white',
borderRightWidth: 1,
}
}}>
<Tab.Screen name="Main" component={Main} />
<Tab.Screen name="Scan" component={Scan} />
<Tab.Screen name="Wallet" component={Wallet} />
<Tab.Screen name="Kowops" component={Kowops} />
</Tab.Navigator>
);
}
export default function BottomNav() {
return (
<MyTabs />
);
}
const styles = StyleSheet.create({
container: {
flex: 2,
backgroundColor:'#ffffff',
padding: 10,
alignItems: 'stretch',
justifyContent: 'space-around'
},
logoContainer: {
height: 120,
padding: 10,
alignItems: 'center' ,
justifyContent: 'flex-end'
},
logo: {
height: 50,
width: 165
},
formContainer: {
flex:1,
alignItems: 'center' ,
justifyContent: 'center'
},
buttonContainer: {
padding: 10,
marginBottom: 20,
width: 250,
alignItems: 'center',
backgroundColor: '#c5e1a5'
},
inputTextField: {
alignItems: 'center',
justifyContent: 'space-between',
padding: 10,
height: 40,
width: 250,
marginBottom: 10,
fontSize: 16,
borderBottomWidth : 1.0,
},
plainText: {
fontSize: 16,
marginBottom: 5,
color: '#59616e',
textDecorationLine: 'underline',
},
actionButtonIcon: {
fontSize: 20,
height: 22,
color: 'white',
},
FABCcontainer: {
height: 22,
},
actionButtonItem: {
},
});
And. the only thing I want to do is change md-create in a plus with outline.
Can anyone help me out?
Thanks a lot!
I also tried to use add-circle-outline from [this icons list][2], but also that didn't work.
The problem in your case is, that you try to use Ionicons v5 wich is not yet implemented in Vector-Icons Icons-Set. If you need to choose an Icon please refer to v4 - https://ionicons.com/v4/
Here you can see the icons that you can use.
md-iconname for android type icons and ios-iconname for apple icons.