156 lines
4.5 KiB
TypeScript
156 lines
4.5 KiB
TypeScript
|
|
/**
|
|||
|
|
* Tab 导航器
|
|||
|
|
* 处理底部标签导航(移动端)
|
|||
|
|
*/
|
|||
|
|
import React from 'react';
|
|||
|
|
import { View } from 'react-native';
|
|||
|
|
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|||
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|||
|
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|||
|
|
|
|||
|
|
import type { MainTabParamList } from './types';
|
|||
|
|
import { colors, shadows } from '../theme';
|
|||
|
|
|
|||
|
|
import { HomeNavigator } from './HomeNavigator';
|
|||
|
|
import { MessageNavigator } from './MessageNavigator';
|
|||
|
|
import { ScheduleNavigator } from './ScheduleNavigator';
|
|||
|
|
import { ProfileNavigator } from './ProfileNavigator';
|
|||
|
|
|
|||
|
|
const Tab = createBottomTabNavigator<MainTabParamList>();
|
|||
|
|
|
|||
|
|
// 常量
|
|||
|
|
const MOBILE_TAB_FLOATING_MARGIN = 12;
|
|||
|
|
|
|||
|
|
interface TabNavigatorProps {
|
|||
|
|
unreadCount: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function TabNavigator({ unreadCount }: TabNavigatorProps) {
|
|||
|
|
const insets = useSafeAreaInsets();
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Tab.Navigator
|
|||
|
|
screenOptions={{
|
|||
|
|
tabBarActiveTintColor: colors.primary.main,
|
|||
|
|
tabBarInactiveTintColor: colors.text.secondary,
|
|||
|
|
tabBarHideOnKeyboard: true,
|
|||
|
|
tabBarStyle: {
|
|||
|
|
backgroundColor: colors.background.paper,
|
|||
|
|
borderTopWidth: 1,
|
|||
|
|
borderTopColor: `${colors.divider}88`,
|
|||
|
|
borderRadius: 24,
|
|||
|
|
marginHorizontal: 14,
|
|||
|
|
marginBottom: MOBILE_TAB_FLOATING_MARGIN + insets.bottom,
|
|||
|
|
height: 64,
|
|||
|
|
paddingBottom: 6,
|
|||
|
|
paddingTop: 8,
|
|||
|
|
paddingHorizontal: 8,
|
|||
|
|
position: 'absolute',
|
|||
|
|
...shadows.lg,
|
|||
|
|
},
|
|||
|
|
tabBarItemStyle: {
|
|||
|
|
borderRadius: 18,
|
|||
|
|
paddingVertical: 1,
|
|||
|
|
marginHorizontal: 2,
|
|||
|
|
},
|
|||
|
|
tabBarLabelStyle: {
|
|||
|
|
fontSize: 12,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
marginTop: -2,
|
|||
|
|
letterSpacing: 0.2,
|
|||
|
|
},
|
|||
|
|
tabBarBadgeStyle: {
|
|||
|
|
backgroundColor: colors.error.main,
|
|||
|
|
color: colors.primary.contrast,
|
|||
|
|
fontSize: 10,
|
|||
|
|
fontWeight: '700',
|
|||
|
|
top: 4,
|
|||
|
|
},
|
|||
|
|
headerShown: false,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Tab.Screen
|
|||
|
|
name="HomeTab"
|
|||
|
|
component={HomeNavigator}
|
|||
|
|
options={{
|
|||
|
|
tabBarLabel: '首页',
|
|||
|
|
tabBarIcon: ({ color, size, focused }) => (
|
|||
|
|
<View style={[styles.tabIconContainer, focused && styles.tabIconActive]}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name={focused ? 'home' : 'home-outline'}
|
|||
|
|
size={focused ? 26 : 24}
|
|||
|
|
color={color}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
),
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
<Tab.Screen
|
|||
|
|
name="MessageTab"
|
|||
|
|
component={MessageNavigator}
|
|||
|
|
options={{
|
|||
|
|
tabBarLabel: '消息',
|
|||
|
|
tabBarBadge: unreadCount > 0 ? (unreadCount > 99 ? '99+' : unreadCount) : undefined,
|
|||
|
|
tabBarIcon: ({ color, size, focused }) => (
|
|||
|
|
<View style={[styles.tabIconContainer, focused && styles.tabIconActive]}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name={focused ? 'message-text' : 'message-text-outline'}
|
|||
|
|
size={focused ? 26 : 24}
|
|||
|
|
color={color}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
),
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
<Tab.Screen
|
|||
|
|
name="ScheduleTab"
|
|||
|
|
component={ScheduleNavigator}
|
|||
|
|
options={{
|
|||
|
|
tabBarLabel: '课表',
|
|||
|
|
tabBarIcon: ({ color, size, focused }) => (
|
|||
|
|
<View style={[styles.tabIconContainer, focused && styles.tabIconActive]}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name={focused ? 'calendar-today' : 'calendar-today'}
|
|||
|
|
size={focused ? 26 : 24}
|
|||
|
|
color={color}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
),
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
<Tab.Screen
|
|||
|
|
name="ProfileTab"
|
|||
|
|
component={ProfileNavigator}
|
|||
|
|
options={{
|
|||
|
|
tabBarLabel: '我的',
|
|||
|
|
tabBarIcon: ({ color, size, focused }) => (
|
|||
|
|
<View style={[styles.tabIconContainer, focused && styles.tabIconActive]}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name={focused ? 'account' : 'account-outline'}
|
|||
|
|
size={focused ? 26 : 24}
|
|||
|
|
color={color}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
),
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
</Tab.Navigator>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
import { StyleSheet } from 'react-native';
|
|||
|
|
|
|||
|
|
const styles = StyleSheet.create({
|
|||
|
|
tabIconContainer: {
|
|||
|
|
alignItems: 'center',
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
width: 38,
|
|||
|
|
height: 30,
|
|||
|
|
borderRadius: 15,
|
|||
|
|
},
|
|||
|
|
tabIconActive: {
|
|||
|
|
backgroundColor: `${colors.primary.main}20`,
|
|||
|
|
transform: [{ translateY: -1 }],
|
|||
|
|
},
|
|||
|
|
});
|