خب در ابتدا یه پروژه با استفاده از Expo میسازیم اگه تا حالا از Expo استفاده نکردید با دستور زیر راحت میتونید نصبش کنید و پروژه جدید رو بسازید !
npm install expo-cli --global expo init AnimatedTabBar cd AnimatedTabBar
خب حالا پروژه جدیدمون ساخته شده یادتون نره نوع پروژه Expo رو Blank نزارید تا با هم پیش بریم :)
tabs several example screens and tabs using react-navigation
بعد از این که پروژمون ساخته شد . پیکیج react-native-animatable رو هم نصبش می کنیم که یکم کارای انیمیشن رو برامون راحت تر کنه .
خب حالا به داخل پوشه navigation میریم و فایل MainTabNavigator.js که ساختار اصلی TabBar ما داخلشه رو باز می کنیم . در کنار این فایل یک فایل با نام TabBar رو می سازیم . خب داخل فایل TabBar مون به صورت زیر کد می زنیم که آیکون و متن شو به صورت کنار هم بزاره :)
/* /src/components/TabBar.js */ import React from "react"; import { View, StyleSheet, TouchableOpacity, Dimensions, Text } from "react-native"; const { width } = Dimensions.get("window"); const Styles = StyleSheet.create({ container: { flexDirection: "row", height: 52, elevation: 2 }, tabButton: { flex: 1, justifyContent: "space-around", alignItems: "center", flexDirection: "row-reverse" }, textStyle: { color: "gray", fontSize: 13 } }); const TabBar = props => { const { renderIcon, getLabelText, activeTintColor, inactiveTintColor, onTabPress, onTabLongPress, getAccessibilityLabel, navigation } = props; const { routes, index: activeRouteIndex } = navigation.state; let type = "slideInUp"; return ( <View style={Styles.container}> {routes.map((route, routeIndex) => { const isRouteActive = routeIndex === activeRouteIndex; const tintColor = isRouteActive ? activeTintColor : inactiveTintColor; return ( <TouchableOpacity key={routeIndex} style={[Styles.tabButton]} onPress={() => { onTabPress({ route }); }} onLongPress={() => { onTabLongPress({ route }); }} accessibilityLabel={getAccessibilityLabel({ route })} > {isRouteActive ? ( <View style={Styles.tabButton}> {renderIcon({ route, focused: isRouteActive, tintColor })} <Text style={Styles.textStyle}>{getLabelText({ route })}</Text> </View> ) : ( <View> {renderIcon({ route, focused: isRouteActive, tintColor })} </View> )} </TouchableOpacity> ); })} </View> ); }; export default TabBar;
خب حالا داخل فایل MainTabNavigator.js باید فایل TabBar رو Import کنیم .
import TabBar from "./TabBar";
خب حالا باید کد زیر رو هم به createBottomTabNavigator مون اضافه کنیم تا کامپونت جدیدمون جایگزین کامپوننت دیفالت برای Tab Bar مون بشه .
{ tabBarComponent: TabBar }
بله حالا باید شکل تب بارمون عوض شده باشه به حالت زیر :
خب حالا یکم به انیمیشن نیاز داریم تا تب بارمون کلی با حال بشه برای اینکار من می خوام روی تب فعالمون یک حالت overLay داشته باشم .
<Animated.View style={[ StyleSheet.absoluteFill, { borderRadius: 25, backgroundColor: "#c6c9ce", width: width / 3, height: 48, top: 2, opacity: 0.5 } ]} />
حالا من یه overlay خیلی نرم ساختم که اضافه اش می کنم به کد TabBar شخصی سازه شده خودمون .
/* /src/components/TabBar.js */ import React from "react"; import { View, StyleSheet, TouchableOpacity, Dimensions, Animated, Text } from "react-native"; const { width } = Dimensions.get("window"); const Styles = StyleSheet.create({ container: { flexDirection: "row", height: 52, elevation: 2 }, tabButton: { flex: 1, justifyContent: "space-around", alignItems: "center", flexDirection: "row-reverse" }, textStyle: { color: "gray", fontSize: 13 } }); const TabBar = props => { const { renderIcon, getLabelText, activeTintColor, inactiveTintColor, onTabPress, onTabLongPress, getAccessibilityLabel, navigation } = props; const { routes, index: activeRouteIndex } = navigation.state; return ( <View style={Styles.container}> <Animated.View style={[ StyleSheet.absoluteFill, { borderRadius: 25, backgroundColor: "#c6c9ce", width: width / 3, height: 48, top: 2, opacity: 0.5 } ]} /> {routes.map((route, routeIndex) => { const isRouteActive = routeIndex === activeRouteIndex; const tintColor = isRouteActive ? activeTintColor : inactiveTintColor; return ( <TouchableOpacity key={routeIndex} style={[Styles.tabButton]} onPress={() => { onTabPress({ route }); }} onLongPress={() => { onTabLongPress({ route }); }} accessibilityLabel={getAccessibilityLabel({ route })} > {isRouteActive ? ( <View style={Styles.tabButton}> {renderIcon({ route, focused: isRouteActive, tintColor })} <Text style={Styles.textStyle}>{getLabelText({ route })}</Text> </View> ) : ( <View> {renderIcon({ route, focused: isRouteActive, tintColor })} </View> )} </TouchableOpacity> ); })} </View> ); }; export default TabBar;
خب حالا یک OverLay خیلی نرم روی تب اول هست ولی خب با کلیک روی تب بعدی جا به جا نمیشه.
خب حالا کافیه overlay خودمون رو وقتی یوزر کلیک می کنه روی تب دیگه ای رو جا به جا کنیم برای اینکار اول باید یه متغیر انیمیشن بسازیم مثل زیر که مقدار اولیش برابر با تب فعالمون هست (دلیلش رو دیگه خودتون حدس بزنید)
let animationValue = new Animated.Value(activeRouteIndex);
هم اکنون با استفاده از transform جذاب overlay رو میخوایم جا به جا کنیم به شکل زیر
<Animated.View style={[ StyleSheet.absoluteFill, { borderRadius: 25, backgroundColor: "#c6c9ce", width: width / 3, height: 48, top: 2, opacity: 0.5 }, { transform: [ { translateX: animationValue.interpolate({ inputRange: [0, 1, 2], outputRange: [0, width / 3, (width / 3) * 2] }) } ] } ]} />
خب حالا می بینیم که با هر بار کلیک روی تب جدید overlay مون میپره روی تب بعدی یعنی جا به جا نمیشه یجورایی خب سخت نگیرید کاری نداره که این بخاطر این مورد هست که با هر بار کلیک رو تب جدید کامپوننت دوباره رندر میشه برای این که این مشکل حل بشه باید قبل اینکه صفحمون جا به جا بشه overlay رو ببریم روی تب جدید و برای اینکه این عمل انجام بشه کافیه قبل عوض شدش route خودمون انیمیشن رو فراخوانی کنیم و مقدارشو از index تب قدیمی به index تب جدید با فاصله .5 ثانیه تغییر بدیم به شکل زیر یعنی به جای
/* onPress={() => { onTabPress({ route }); }} */
باید کد زیر رو قرار بدیم .
onPress={() => { Animated.timing(animationValue, { toValue: routeIndex, duration: 500, useNativeDriver: true }).start(() => { onTabPress({ route }); }); }}
به همین راحتی و هم اکنون می تونیم مشاهده کنیم که بلهههه بلاخره یکم جذاب تر شده طراحیمون .
و هم اکنون قسمت اولمون به پایان رسید :) ایشالله توی قسمت دوم مشکلات رو رفع می کنیم و کلی قشنگترش می کنیم .
آدرس گیت هاب پروژه : https://github.com/AZIMAT/AnimatedTabBar