reanimated-bottom-tabs
Version:
Bottom Tabs for react-navigation using reanimated
131 lines (122 loc) • 3.07 kB
JavaScript
import React from "react";
import { View, StyleSheet, Dimensions } from "react-native";
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
} from "react-native-reanimated";
import TabItem from "./components/TabItem";
const { width } = Dimensions.get("window");
const AnimatedTabBar = ({
state,
navigation,
descriptors,
activeColor,
margin = 8,
moverPadding = 5,
moverStyle = {
backgroundColor: "#e74c3c",
borderRadius: 10,
},
contentContainerStyle = {
backgroundColor: "#181818",
borderRadius: 14,
elevation: 3,
},
itemLabelStyle,
}) => {
//number of routes for calculating width
const numberOrRoutes = state.routes.length;
const thing = useSharedValue(0);
//width of bottom tab based on margin
const bottomTabWidth = width - margin * 2;
// width of each item = width of mover
const itemWidth = bottomTabWidth / numberOrRoutes;
const sz = useAnimatedStyle(() => {
return {
transform: [
{
translateX: withSpring(thing.value, {
stiffness: 80, //default: 100
damping: 20, //default: 10
mass: 0.2, //default: 1
}),
},
],
};
});
const onTabPress = (route, index) => {
const event = navigation.emit({
type: "tabPress",
target: route.key,
canPreventDefault: true,
});
const isFocused = state.index === index;
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
thing.value = bottomTabWidth * (index / numberOrRoutes);
}
};
const onTabLongPress = (route) => {
navigation.emit({
type: "tabLongPress",
target: route.key,
});
};
return (
<View
style={[
{ ...contentContainerStyle },
{ margin },
{
flexDirection: "row",
position: "absolute",
bottom: 0,
left: 0,
right: 0,
},
]}
>
<Animated.View
style={[s.mover, { width: itemWidth }, { padding: moverPadding }, sz]}
>
<View
style={[
moverStyle,
{
width: "100%",
height: "100%",
},
]}
/>
</Animated.View>
{state.routes.map((route, index) => {
return (
<TabItem
activeColor={activeColor}
key={route.key}
route={route}
index={index}
state={state}
descriptors={descriptors}
onTabPress={onTabPress}
onTabLongPress={onTabLongPress}
itemWidth={itemWidth}
itemLabelStyle={itemLabelStyle}
/>
);
})}
</View>
);
};
const s = StyleSheet.create({
mover: {
position: "absolute",
top: 0,
left: 0,
height: "100%",
alignItems: "center",
justifyContent: "center",
},
});
export default AnimatedTabBar;