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 ❤️