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={{
|
animate={{
|
||||||
tintColor: focused ? Palette.white : "#8B8883",
|
tintColor: focused ? Palette.white : "#8B8883",
|
||||||
}}
|
}}
|
||||||
|
transition={{ type: "spring", damping: 18, mass: 0.7 }}
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
width: Platform.OS === "web" ? 30 : 24,
|
width: Platform.OS === "web" ? 30 : 24,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { Motion } from "@legendapp/motion";
|
||||||
import * as Haptics from "expo-haptics";
|
import * as Haptics from "expo-haptics";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { Text, TouchableOpacity, View } from "react-native";
|
import { Text, TouchableOpacity, View } from "react-native";
|
||||||
|
|
||||||
import ItemContainer from "../components/ItemContainer/ItemContainer";
|
import ItemContainer from "../components/ItemContainer/ItemContainer";
|
||||||
@@ -9,6 +10,7 @@ import { FONT_FAMILY } from "../styles/Fonts";
|
|||||||
|
|
||||||
const TabBar = ({ state = {}, descriptors = {}, navigation = {} }) => {
|
const TabBar = ({ state = {}, descriptors = {}, navigation = {} }) => {
|
||||||
const { isWeb } = useLayoutType();
|
const { isWeb } = useLayoutType();
|
||||||
|
const [pressedIndex, setPressedIndex] = useState(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
@@ -87,18 +89,34 @@ const TabBar = ({ state = {}, descriptors = {}, navigation = {} }) => {
|
|||||||
testID={options.tabBarTestID}
|
testID={options.tabBarTestID}
|
||||||
onPress={_onPressTabBar}
|
onPress={_onPressTabBar}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
|
onPressIn={() => setPressedIndex(index)}
|
||||||
|
onPressOut={() => setPressedIndex(null)}
|
||||||
>
|
>
|
||||||
{options?.tabBarIcon({ focused: isFocused })}
|
<Motion.View
|
||||||
<Text
|
animate={{
|
||||||
|
scale: isFocused
|
||||||
|
? 1.12
|
||||||
|
: pressedIndex === index
|
||||||
|
? 1.05
|
||||||
|
: 1,
|
||||||
|
}}
|
||||||
|
transition={{ type: "spring", damping: 18, mass: 0.7 }}
|
||||||
style={{
|
style={{
|
||||||
fontSize: isWeb ? 14 : 10,
|
...Style.containerCenter,
|
||||||
color: isFocused ? Palette.white : "#8B8883",
|
|
||||||
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
|
|
||||||
marginTop: 2,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{options?.tabBarIcon({ focused: isFocused })}
|
||||||
</Text>
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: isWeb ? 14 : 10,
|
||||||
|
color: isFocused ? Palette.white : "#8B8883",
|
||||||
|
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
|
||||||
|
marginTop: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
</Motion.View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user