import type { BottomTabNavigationOptions } from '@react-navigation/bottom-tabs'; import { GlassContainer, GlassView, isLiquidGlassAvailable } from 'expo-glass-effect'; import * as Haptics from 'expo-haptics'; import { Tabs, usePathname } from 'expo-router'; import { Icon, Label, NativeTabs } from 'expo-router/unstable-native-tabs'; import { useTranslation } from 'react-i18next'; import React from 'react'; import { Text, TouchableOpacity, View, ViewStyle } from 'react-native'; import { IconSymbol } from '@/components/ui/IconSymbol'; import { Colors } from '@/constants/Colors'; import { ROUTES } from '@/constants/Routes'; import { TAB_BAR_BOTTOM_OFFSET, TAB_BAR_HEIGHT } from '@/constants/TabBar'; import { useAppSelector } from '@/hooks/redux'; import { useColorScheme } from '@/hooks/useColorScheme'; import { selectEnabledTabs } from '@/store/tabBarConfigSlice'; // Tab configuration type TabConfig = { icon: string; titleKey: string; }; const TAB_CONFIGS: Record = { statistics: { icon: 'chart.pie.fill', titleKey: 'health.tabs.health' }, medications: { icon: 'pills.fill', titleKey: 'health.tabs.medications' }, fasting: { icon: 'timer', titleKey: 'health.tabs.fasting' }, challenges: { icon: 'trophy.fill', titleKey: 'health.tabs.challenges' }, personal: { icon: 'person.fill', titleKey: 'health.tabs.personal' }, }; export default function TabLayout() { const { t } = useTranslation(); const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; const colorTokens = Colors[theme]; const pathname = usePathname(); const glassEffectAvailable = isLiquidGlassAvailable(); // 获取已启用的标签配置(按自定义顺序) const enabledTabs = useAppSelector(selectEnabledTabs); // Helper function to determine if a tab is selected const isTabSelected = (routeName: string): boolean => { const routeMap: Record = { statistics: ROUTES.TAB_STATISTICS, medications: ROUTES.TAB_MEDICATIONS, fasting: ROUTES.TAB_FASTING, challenges: ROUTES.TAB_CHALLENGES, personal: ROUTES.TAB_PERSONAL, }; return routeMap[routeName] === pathname || pathname.includes(routeName); }; // Custom tab button component const createTabButton = (routeName: string) => (props: any) => { const { onPress } = props; const tabConfig = TAB_CONFIGS[routeName]; if (!tabConfig) return null; const isSelected = isTabSelected(routeName); const handlePress = (event: any) => { if (process.env.EXPO_OS === 'ios') { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); } onPress?.(event); }; return ( {isSelected && ( {t(tabConfig.titleKey)} )} ); }; // Custom tab bar background component const TabBarBackground = () => { if (glassEffectAvailable) { return ( ); } return null; }; // Common screen options const getScreenOptions = (routeName: string): BottomTabNavigationOptions => ({ headerShown: false, tabBarActiveTintColor: colorTokens.tabIconSelected, tabBarButton: createTabButton(routeName), tabBarBackground: TabBarBackground, tabBarStyle: { position: 'absolute', bottom: TAB_BAR_BOTTOM_OFFSET, height: TAB_BAR_HEIGHT, borderRadius: 34, backgroundColor: glassEffectAvailable ? 'transparent' : colorTokens.tabBarBackground, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: glassEffectAvailable ? 0.1 : 0.2, shadowRadius: 10, elevation: 5, paddingHorizontal: 6, paddingTop: 0, paddingBottom: 0, marginHorizontal: 16, left: 16, right: 16, alignSelf: 'center', borderWidth: glassEffectAvailable ? 1 : 0, borderColor: glassEffectAvailable ? (theme === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)') : 'transparent', } as ViewStyle, tabBarItemStyle: { backgroundColor: 'transparent', height: TAB_BAR_HEIGHT, marginTop: 0, marginBottom: 0, paddingTop: 0, paddingBottom: 0, }, tabBarShowLabel: false, }); // 根据配置渲染标签页 if (glassEffectAvailable) { return ( {enabledTabs.map((tab) => { const tabConfig = TAB_CONFIGS[tab.id]; if (!tabConfig) return null; return ( ); })} ); } // 确定初始路由(第一个启用的标签) const initialRouteName = enabledTabs.length > 0 ? enabledTabs[0].id : 'statistics'; return ( getScreenOptions(route.name)} > {enabledTabs.map((tab) => { const tabConfig = TAB_CONFIGS[tab.id]; if (!tabConfig) return null; return ( ); })} ); }