<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Baptiste Arnaud</title>
    <description>The latest articles on Forem by Baptiste Arnaud (@baptistearnaud).</description>
    <link>https://forem.com/baptistearnaud</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F248506%2Ff6b159e1-a8bb-4633-a9e4-929084651c33.jpeg</url>
      <title>Forem: Baptiste Arnaud</title>
      <link>https://forem.com/baptistearnaud</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/baptistearnaud"/>
    <language>en</language>
    <item>
      <title>Animated Sliding tab bar in React Native</title>
      <dc:creator>Baptiste Arnaud</dc:creator>
      <pubDate>Wed, 08 Apr 2020 10:16:17 +0000</pubDate>
      <link>https://forem.com/baptistearnaud/animated-sliding-tab-bar-in-react-native-58pb</link>
      <guid>https://forem.com/baptistearnaud/animated-sliding-tab-bar-in-react-native-58pb</guid>
      <description>&lt;p&gt;I'll show you in this tutorial how to make this cool animated custom bottom tab bar using React Navigation.&lt;/p&gt;

&lt;p&gt;
    &lt;a href="https://i.giphy.com/media/ZZfnKe0Ccwq15vzf6E/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img width="500" alt="typescript-starter dark logo" src="https://i.giphy.com/media/ZZfnKe0Ccwq15vzf6E/giphy.gif"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;In order to do this, I found this great tutorial by &lt;a href="https://dev.to/ksushiva"&gt;@ksushiva&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/ksushiva/animated-sliding-tab-bar-in-react-native-56nb"&gt;https://dev.to/ksushiva/animated-sliding-tab-bar-in-react-native-56nb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But unfortunately, it's already outdated due to the recent publication of React Navigation v5. And it comes with &lt;a href="https://reactnavigation.org/docs/upgrading-from-4.x/"&gt;lots of modifications&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dependencies
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @react-navigation/native

npm install @react-navigation/bottom-tabs

expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Custom MenuItem
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { View } from "react-native";
import { blue, grey } from "../../styles";
import { AntDesign } from "@expo/vector-icons";
type Props = {
  iconName: string;
  isCurrent?: boolean;
};
export const BottomMenuItem = ({ iconName, isCurrent }: Props) =&amp;gt; {
  return (
    &amp;lt;View
      style={{
        height: "100%",
        justifyContent: "center",
        alignItems: "center",
      }}
    &amp;gt;
      &amp;lt;AntDesign
        name={iconName}
        size={32}
        style={{ color: isCurrent ? blue : grey }}
      /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This represented each item in the tab bar. You can adjust this component with anything you want. Here it requires an &lt;code&gt;iconName&lt;/code&gt; in order to display the correct icon and a &lt;code&gt;isCurrent&lt;/code&gt; property which changes the icon color if it is currently selected.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Custom TabBar component
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import {
  View,
  TouchableOpacity,
  Dimensions,
  StyleSheet,
} from "react-native";
import { BottomTabBarProps } from "@react-navigation/bottom-tabs";
import { BottomMenuItem } from "./BottomMenuItem";
import { blue } from "../../styles";
export const TabBar = ({
  state,
  descriptors,
  navigation,
}: BottomTabBarProps) =&amp;gt; {
  const totalWidth = Dimensions.get("window").width;
  const tabWidth = totalWidth / state.routes.length;
  return (
    &amp;lt;View style={[style.tabContainer, { width: totalWidth }]}&amp;gt;
      &amp;lt;View style={{ flexDirection: "row" }}&amp;gt;
        &amp;lt;View style={style.slider}/&amp;gt;
{state.routes.map((route, index) =&amp;gt; {
          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 = () =&amp;gt; {
            const event = navigation.emit({
              type: "tabPress",
              target: route.key,
              canPreventDefault: true,
            });
if (!isFocused &amp;amp;&amp;amp; !event.defaultPrevented) {
              navigation.navigate(route.name);
            }
const onLongPress = () =&amp;gt; {
            navigation.emit({
              type: "tabLongPress",
              target: route.key,
            });
          };
return (
            &amp;lt;TouchableOpacity
              accessibilityRole="button"
              accessibilityStates={isFocused ? ["selected"] : []}
              accessibilityLabel={options.tabBarAccessibilityLabel}
              testID={options.tabBarTestID}
              onPress={onPress}
              onLongPress={onLongPress}
              style={{ flex: 1 }}
              key={index}
            &amp;gt;
              &amp;lt;BottomMenuItem
                iconName={label.toString()}
                isCurrent={isFocused}
              /&amp;gt;
            &amp;lt;/TouchableOpacity&amp;gt;
          );
        })}
      &amp;lt;/View&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};
const style = StyleSheet.create({
  tabContainer: {
    height: 60,
    shadowOffset: {
      width: 0,
      height: -1,
    },
    shadowOpacity: 0.1,
    shadowRadius: 4.0,
    backgroundColor: "white",
    borderTopRightRadius: 20,
    borderTopLeftRadius: 20,
    elevation: 10,
    position: "absolute",
    bottom: 0,
  },
  slider: {
    height: 5,
    position: "absolute",
    top: 0,
    left: 10,
    backgroundColor: blue,
    borderRadius: 10,
    width: 50
},
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Connect the custom TabBar to the Navigation System (BottomMenu component)
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import {
  createBottomTabNavigator,
  BottomTabBarProps,
} from "@react-navigation/bottom-tabs";
import { TabBar } from "./TabBar";
import { AppsScreen } from "../../screens/AppsScreen";
import { DashboardScreen } from "../../screens/DashboardScreen";
import { GroupScreen } from "../../screens/GroupScreen";
import { ProfileScreen } from "../../screens/ProfileScreen";
import { useSafeArea } from "react-native-safe-area-context";
import { View } from "react-native";
export const BottomMenu = () =&amp;gt; {
  const Tab = createBottomTabNavigator();
  return (
    &amp;lt;View style={{ flex: 1, position: "relative"}}&amp;gt;
      &amp;lt;Tab.Navigator
        tabBar={(props: BottomTabBarProps) =&amp;gt; &amp;lt;TabBar {...props} /&amp;gt;}
      &amp;gt;
        &amp;lt;Tab.Screen name="search1" component={AppsScreen} /&amp;gt;
        &amp;lt;Tab.Screen name="dashboard" component={DashboardScreen} /&amp;gt;
        &amp;lt;Tab.Screen name="profile" component={GroupScreen} /&amp;gt;
        &amp;lt;Tab.Screen name="user" component={ProfileScreen} /&amp;gt;
      &amp;lt;/Tab.Navigator&amp;gt;
      {useSafeArea().bottom &amp;gt; 0 &amp;amp;&amp;amp; (
        &amp;lt;View
          style={{
            height: useSafeArea().bottom - 5,
            backgroundColor: "white",
          }}
        /&amp;gt;
      )}
    &amp;lt;/View&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;we use the &lt;code&gt;useSafeArea&lt;/code&gt; piece of code in order to render our tab bar higher if there is the horizontal bar on the recent iOS devices for example.&lt;/p&gt;

&lt;p&gt;Then you simply have to place this &lt;code&gt;BottomMenu&lt;/code&gt; anywhere. In &lt;code&gt;App&lt;/code&gt; component for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { NavigationContainer } from "@react-navigation/native";
import {BottomMenu} from "./src/components/BottomMenu/BottomMenu";
export default function App() {
  return (
    &amp;lt;NavigationContainer&amp;gt;
      &amp;lt;SafeAreaProvider&amp;gt;
          &amp;lt;BottomMenu/&amp;gt;
      &amp;lt;/SafeAreaProvider&amp;gt;
    &amp;lt;/NavigationContainer&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now you should have the bottom tab bar on your app but we need to animate the "slider" now.&lt;/p&gt;

&lt;p&gt;So in the &lt;code&gt;TabBar&lt;/code&gt; component, you need:&lt;br&gt;
To add a state variable :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [translateValue] = useState(new Animated.Value(0));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To change the current &lt;code&gt;View&lt;/code&gt; representing the slider to :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Animated.View
          style={[
            style.slider,
            {
              transform: [{ translateX: translateValue }],
              width: tabWidth - 20,
            },
          ]}
        /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And finally, in the &lt;code&gt;onPress&lt;/code&gt; function, add this piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Animated.spring(translateValue, {
              toValue: index * tabWidth,
              velocity: 10,
              useNativeDriver: true,
            }).start();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;You can find the entire code example in this repository:&lt;br&gt;
&lt;a href="https://github.com/baptisteArnaud/animated-bottom-tab-react-native-example"&gt;https://github.com/baptisteArnaud/animated-bottom-tab-react-native-example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to post a comment on this tutorial if you need help.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>animation</category>
      <category>reactnavigation</category>
    </item>
  </channel>
</rss>
