Files
workspace/code/app/app-rn3/components/common/tabbar.tsx
T
2026-04-09 21:37:11 +08:00

130 lines
2.7 KiB
TypeScript

import type { Href } from "expo-router";
import { usePathname, useRouter } from "expo-router";
import { useEffect, useState } from "react";
import { Pressable, Text, View } from "react-native";
import Animated, {
useAnimatedStyle,
useSharedValue,
withSequence,
withTiming,
} from "react-native-reanimated";
import * as icons from "lucide-react-native/icons";
import { BlurView } from "expo-blur";
export interface TabbarItem {
name: string;
href: Href;
icon: keyof typeof icons;
label: string;
onPress?: () => void;
}
interface AppTabbarProps {
data: TabbarItem[];
}
function TabButton({
iconName,
label,
isFocused = false,
onPress,
}: {
iconName: keyof typeof icons;
label: string;
isFocused?: boolean;
onPress?: () => void;
}) {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
useEffect(() => {
if (isFocused) {
scale.value = withSequence(
withTiming(0.9, { duration: 120 }),
withTiming(1, { duration: 160 }),
);
}
}, [isFocused]);
const LucideIcon = icons[iconName];
return (
<Pressable
onPress={onPress}
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
}}
>
<Animated.View style={animatedStyle}>
<LucideIcon size={22} color={isFocused ? "#111" : "#999"} strokeWidth={2} />
<Text
style={{
fontSize: 10,
marginTop: 2,
color: isFocused ? "#111" : "#999",
}}
>
{label}
</Text>
</Animated.View>
</Pressable>
);
}
export default function CustomTabbar({ data }: AppTabbarProps) {
const router = useRouter();
const pathname = usePathname();
const [activeTab, setActiveTab] = useState("");
useEffect(() => {
const match = data.find((item) => item.href === pathname);
if (match) {
setActiveTab(match.name);
}
}, [pathname, data]);
const handlePressTab = (item: TabbarItem) => {
setActiveTab(item.name);
router.push(item.href);
item.onPress?.();
};
return (
<View
style={{
position: "absolute",
bottom: 0,
left: 0,
right: 0,
}}
>
<BlurView
intensity={90}
tint="light"
blurMethod="dimezisBlurView"
style={{
flexDirection: "row",
height: 56,
}}
>
{data.map((item) => (
<TabButton
key={item.name}
iconName={item.icon}
label={item.label}
isFocused={activeTab === item.name}
onPress={() => handlePressTab(item)}
/>
))}
</BlurView>
</View>
);
}