You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
3.2 KiB
143 lines
3.2 KiB
/** |
|
* 快速底部导航组件 |
|
* |
|
* 深色主题特有,提供快速导航,使用真实数据 |
|
*/ |
|
|
|
import React, { useState, useEffect } from 'react'; |
|
import { |
|
View, |
|
Text, |
|
StyleSheet, |
|
TouchableOpacity, |
|
ScrollView, |
|
Animated, |
|
} from 'react-native'; |
|
import { createThemeStyles } from '@/theme'; |
|
import Colors from '@/constants/Colors'; |
|
import { mockNavItems } from '@/services/mockHomeService'; |
|
import type { NavItem } from '@/types/home'; |
|
|
|
/** |
|
* 创建主题样式 |
|
*/ |
|
const styles = createThemeStyles((colors) => ({ |
|
container: { |
|
backgroundColor: colors.backgroundSecondary, |
|
paddingVertical: 12, |
|
paddingHorizontal: 12, |
|
borderTopWidth: 1, |
|
borderTopColor: colors.border, |
|
}, |
|
scrollView: { |
|
paddingHorizontal: 0, |
|
}, |
|
navItem: { |
|
paddingHorizontal: 14, |
|
paddingVertical: 10, |
|
marginRight: 10, |
|
borderRadius: 8, |
|
backgroundColor: colors.background, |
|
justifyContent: 'center', |
|
alignItems: 'center', |
|
minWidth: 75, |
|
elevation: 2, |
|
shadowColor: colors.cardShadow, |
|
shadowOffset: { width: 0, height: 1 }, |
|
shadowOpacity: 0.1, |
|
shadowRadius: 2, |
|
}, |
|
navItemActive: { |
|
backgroundColor: colors.primary, |
|
}, |
|
navIcon: { |
|
fontSize: 22, |
|
marginBottom: 4, |
|
}, |
|
navText: { |
|
fontSize: 12, |
|
color: colors.text, |
|
textAlign: 'center', |
|
fontWeight: '500', |
|
}, |
|
navTextActive: { |
|
color: '#FFFFFF', |
|
}, |
|
})); |
|
|
|
interface FastFootNavProps { |
|
theme: 'light' | 'dark'; |
|
items?: NavItem[]; |
|
onTabPress?: (tabId: string, action: string) => void; |
|
} |
|
|
|
/** |
|
* 快速底部导航组件 |
|
*/ |
|
export default function FastFootNav({ theme, items: propItems, onTabPress }: FastFootNavProps) { |
|
const s = styles[theme]; |
|
const [items, setItems] = useState<NavItem[]>(propItems || []); |
|
const [selectedId, setSelectedId] = useState<string | null>(null); |
|
|
|
// 加载导航项数据 |
|
useEffect(() => { |
|
if (propItems && propItems.length > 0) { |
|
setItems(propItems); |
|
return; |
|
} |
|
|
|
const loadItems = async () => { |
|
try { |
|
// const data = await getNavItems(); |
|
// setItems(data.length > 0 ? data : mockNavItems); |
|
} catch (error) { |
|
console.error('加载导航项失败:', error); |
|
setItems(mockNavItems); |
|
} |
|
}; |
|
loadItems(); |
|
}, [propItems]); |
|
|
|
const handleNavPress = (item: NavItem) => { |
|
setSelectedId(item.id); |
|
onTabPress?.(item.id, item.action); |
|
}; |
|
|
|
if (items.length === 0) { |
|
return null; |
|
} |
|
|
|
return ( |
|
<View style={s.container}> |
|
<ScrollView |
|
style={s.scrollView} |
|
horizontal |
|
showsHorizontalScrollIndicator={false} |
|
scrollEventThrottle={16} |
|
> |
|
{items.map((item) => ( |
|
<TouchableOpacity |
|
key={item.id} |
|
style={[ |
|
s.navItem, |
|
selectedId === item.id && s.navItemActive, |
|
]} |
|
onPress={() => handleNavPress(item)} |
|
activeOpacity={0.7} |
|
> |
|
<Text style={s.navIcon}>{item.icon || '🎮'}</Text> |
|
<Text |
|
style={[ |
|
s.navText, |
|
selectedId === item.id && s.navTextActive, |
|
]} |
|
> |
|
{item.name} |
|
</Text> |
|
</TouchableOpacity> |
|
))} |
|
</ScrollView> |
|
</View> |
|
); |
|
} |
|
|
|
|