Here's what are we going to implement but without The Pose Effect, which will be added later in a separate article.
First of all, Let's setup our Tab.Navigator to Support Custom TabBar Components, By adding the following code in MainTabs.tsx file
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import TabBar from './TabBar';
import Home from '../Stack/Home';
import Categoryfrom '../Stack/Category';
import Offers from '../Stack/Offers';
import Account from '../Stack/Account';
import Cart from '../Stack/Cart';
const Tab = createBottomTabNavigator();
const TabNavigator: React.FC = () => {
const tabs = [
{
name: 'Home',
label: 'Home',
component: Home,
},
{
name: 'Category',
label: 'Category',
component: Category,
},
{
name: 'Offers',
label: 'Offers',
component: Offers,
},
{
name: 'Account',
label: 'Account',
component: Account,
},
{
name: 'Cart',
label: 'Cart',
component: Cart,
},
];
return (
<Tab.Navigator
tabBar={(props) => <TabBar {...props} />}
initialRouteName={'Home'}
>
{tabs.map((_, index) => {
return (
<Tab.Screen
key={index}
name={_.name}
component={_.component}
options={{
tabBarLabel: _.label,
}}
/>
);
})}
</Tab.Navigator>
);
};
export default TabNavigator;
Now we have to create our TabBar Component which will support the Animation by Adding the following code into our TabBar.tsx file
import React, { useEffect, useRef } from 'react';
import { COLORS, DEVICE_HEIGHT as height, DEVICE_WIDTH as width, ICONS } from '../../common';
import { AppIcon, AppText } from '../../components';
import { StyleSheet, View, TouchableWithoutFeedback, Animated } from 'react-native';
const TAB_BAR_WIDTH = width / 5;
const ANIMATED_PART_HEIGHT = 5;
const TabBar = ({ state, descriptors, navigation }) => {
const animationHorizontalValue = useRef(new Animated.Value(0)).current;
const animate = (index) => {
Animated.spring(animationHorizontalValue, {
toValue: index * TAB_BAR_WIDTH,
useNativeDriver: true,
}).start();
};
useEffect(() => {
animate(state.index);
}, [state.index]);
return (
<View style={styles.container}>
<Animated.View style={styles.animatedWrapper}>
<Animated.View
style={[
styles.animatedView,
{
transform: [{ translateX: animationHorizontalValue }],
},
]}
/>
</Animated.View>
<View style={{ flexDirection: 'row' }}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label = options.tabBarLabel || 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 onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
return (
<TouchableWithoutFeedback
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
style={styles.tabButton}
key={`${index}--${route.key}`}
>
<View style={styles.innerView}>
<AppIcon name={label} color={isFocused ? COLORS.main : COLORS.black} />
<AppText numberOfLines={1} type="heavy" style={[styles.iconText, { color: isFocused ? COLORS.main : COLORS.black }]}>
{label}
</AppText>
</View>
</TouchableWithoutFeedback>
);
})}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'column',
borderTopColor: COLORS.gray,
borderTopWidth: 0.5,
backgroundColor: COLORS.white,
},
tabButton: {
flex: 1,
},
innerView: {
paddingVertical: height * 0.01,
justifyContent: 'center',
alignItems: 'center',
},
iconText: {
width: TAB_BAR_WIDTH,
textAlign: 'center',
},
animatedView: {
width: TAB_BAR_WIDTH,
height: ANIMATED_PART_HEIGHT,
backgroundColor: COLORS.main,
},
animatedWrapper: { width: TAB_BAR_WIDTH, alignItems: 'center', justifyContent: 'center' },
});
export default TabBar;
As we can see, It's very easy to implement, nothing much to explain.
Happy Coding ❤
Top comments (1)
Great, best of luck ❤️