animated tab bar
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { Pressable } from "react-native";
|
||||
import Animated, {
|
||||
cancelAnimation,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
withSpring,
|
||||
} from "react-native-reanimated";
|
||||
|
||||
export default function PressableScale({
|
||||
children,
|
||||
onPress,
|
||||
style,
|
||||
contentStyle,
|
||||
hitSlop = 8,
|
||||
disabled = false,
|
||||
scaleTo = 1.5,
|
||||
spring = { damping: 18, stiffness: 220, mass: 0.8 },
|
||||
...rest
|
||||
}) {
|
||||
const sv = useSharedValue(1);
|
||||
|
||||
const rStyle = useAnimatedStyle(() => ({
|
||||
transform: [{ scale: sv.value }],
|
||||
}));
|
||||
|
||||
const pressIn = useCallback(() => {
|
||||
if (disabled) return;
|
||||
cancelAnimation(sv);
|
||||
sv.value = 1;
|
||||
sv.value = withSpring(scaleTo, spring);
|
||||
}, [disabled, scaleTo, spring, sv]);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
cancelAnimation(sv);
|
||||
sv.value = withSpring(1, spring);
|
||||
}, [spring, sv]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
cancelAnimation(sv);
|
||||
sv.value = 1;
|
||||
},
|
||||
[sv]
|
||||
);
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
onPressIn={pressIn}
|
||||
onPressOut={reset}
|
||||
onTouchCancel={reset}
|
||||
onHoverOut={reset} // web
|
||||
onMouseUp={reset} // web
|
||||
onMouseLeave={reset} // web
|
||||
onBlur={reset}
|
||||
onPress={(e) => {
|
||||
onPress?.(e);
|
||||
reset();
|
||||
}}
|
||||
hitSlop={hitSlop}
|
||||
disabled={disabled}
|
||||
style={style}
|
||||
{...rest}
|
||||
>
|
||||
<Animated.View style={[contentStyle, rStyle]}>{children}</Animated.View>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
@@ -25,6 +25,7 @@ export const BottomTabScreen = () => {
|
||||
animate={{
|
||||
tintColor: focused ? Palette.white : "#8B8883",
|
||||
}}
|
||||
transition={{ type: "spring", damping: 18, mass: 0.7 }}
|
||||
style={[
|
||||
{
|
||||
width: Platform.OS === "web" ? 30 : 24,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Motion } from "@legendapp/motion";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Text, TouchableOpacity, View } from "react-native";
|
||||
|
||||
import ItemContainer from "../components/ItemContainer/ItemContainer";
|
||||
@@ -9,6 +10,7 @@ import { FONT_FAMILY } from "../styles/Fonts";
|
||||
|
||||
const TabBar = ({ state = {}, descriptors = {}, navigation = {} }) => {
|
||||
const { isWeb } = useLayoutType();
|
||||
const [pressedIndex, setPressedIndex] = useState(null);
|
||||
|
||||
return (
|
||||
<View
|
||||
@@ -87,18 +89,34 @@ const TabBar = ({ state = {}, descriptors = {}, navigation = {} }) => {
|
||||
testID={options.tabBarTestID}
|
||||
onPress={_onPressTabBar}
|
||||
onLongPress={onLongPress}
|
||||
onPressIn={() => setPressedIndex(index)}
|
||||
onPressOut={() => setPressedIndex(null)}
|
||||
>
|
||||
{options?.tabBarIcon({ focused: isFocused })}
|
||||
<Text
|
||||
<Motion.View
|
||||
animate={{
|
||||
scale: isFocused
|
||||
? 1.12
|
||||
: pressedIndex === index
|
||||
? 1.05
|
||||
: 1,
|
||||
}}
|
||||
transition={{ type: "spring", damping: 18, mass: 0.7 }}
|
||||
style={{
|
||||
fontSize: isWeb ? 14 : 10,
|
||||
color: isFocused ? Palette.white : "#8B8883",
|
||||
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
|
||||
marginTop: 2,
|
||||
...Style.containerCenter,
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
{options?.tabBarIcon({ focused: isFocused })}
|
||||
<Text
|
||||
style={{
|
||||
fontSize: isWeb ? 14 : 10,
|
||||
color: isFocused ? Palette.white : "#8B8883",
|
||||
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
|
||||
marginTop: 2,
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</Motion.View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user