This commit is contained in:
oneao committed 2026-04-08 21:28:52 +08:00
1 parent f28107399e
commit 7823fe2768
13 files changed
+294 -28

No files matched your search

@@ -0,0 +1,127 @@
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";
export interface TabbarItem {
name: string;
href: Href;
icon: keyof typeof icons; // 👈 传 icon 名字
label: string; // 👈 label
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]);
// 👇 在内部统一处理 icon
const LucideIcon = icons[iconName];
return (
<Pressable
onPress={onPress}
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
}}
>
<Animated.View style={animatedStyle}>
<LucideIcon
size={22}
color={"#333"}
fill={isFocused ? "#0284c7" : "#fff"} // 填充颜色
strokeWidth={2}
/>
<Text
style={{
fontSize: 10,
marginTop: 2,
color: "#333",
}}
>
{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={{
flexDirection: "row",
height: 48,
alignItems: "center",
backgroundColor: "#fff",
}}
>
{data.map((item) => (
<TabButton
key={item.name}
iconName={item.icon}
label={item.label}
isFocused={activeTab === item.name}
onPress={() => handlePressTab(item)}
/>
))}
</View>
);
}