This commit is contained in:
oneao committed 2026-01-26 17:29:24 +08:00
1 parent 8f3f6982db
commit 5a79414319
10 files changed
+355 -293

No files matched your search

@@ -1,11 +1,80 @@
import { TabSlot } from 'expo-router/ui'
import { Text, View } from 'react-native'
import type { icons } from 'lucide-react-native'
import type { SortableGridRenderItem } from 'react-native-sortables'
import { Slot, usePathname, useRouter } from 'expo-router'
import { useCallback, useEffect, useState } from 'react'
import { Pressable, Text, TouchableOpacity, Vibration, View } from 'react-native'
import Animated, { useAnimatedRef } from 'react-native-reanimated'
import Sortable from 'react-native-sortables'
import { ADrawer, LucideIcon } from '@/components/common/ao'
interface NavItem {
label: string
path: string
icon: keyof typeof icons
}
const NAV_MENUS: NavItem[] = [
{ label: '记账', path: '/money', icon: 'CircleDollarSign' },
{ label: '恋爱记', path: '/love', icon: 'Heart' },
{ label: '聊天', path: '/chat', icon: 'MessageCircle' },
{ label: '个人中心', path: '/user', icon: 'CircleUserRound' },
]
export default function TabsLayout() {
const scrollableRef = useAnimatedRef<Animated.ScrollView>()
const router = useRouter()
const pathname = usePathname()
const [showNavDrawer, setShowNavDrawer] = useState(false)
const [draggingId, setDraggingId] = useState<string>('')
const [currentNav, setCurrentNav] = useState<NavItem>({
label: '',
path: '',
icon: 'AArrowDown',
})
useEffect(() => {
const current = NAV_MENUS.find(item => item.path === pathname)
if (current) {
setCurrentNav(current)
}
}, [pathname])
const refreshPage = () => {
router.replace(pathname)
}
const renderNavItem = useCallback<SortableGridRenderItem<NavItem>>(
({ item }) => (
<Pressable
className="
flex
flex-col
items-center
justify-center
bg-[white]
rounded-md
shadow-md
p-3
"
onPress={() => {
setShowNavDrawer(false)
router.push(item.path)
}}
>
<LucideIcon icon={item.icon} size={24} strokeWidth={2} clickable={false} />
<Text className="text-sm mt-2">
{item.label}
</Text>
</Pressable>
),
[],
)
return (
<View className="flex-1 bg-gray-100">
<View className="flex-1 px-4 pt-4 pb-24">
<TabSlot />
<View className="flex-1 bg-white">
<Slot />
</View>
<View
@@ -18,10 +87,55 @@ export default function TabsLayout() {
gap-4
"
>
<View className="bg-white rounded-md shadow-lg h-12 w-12"></View>
<View className="flex-1 bg-white rounded-md shadow-lg h-12"></View>
<View className="bg-white rounded-md shadow-lg h-12 w-12"></View>
<View className="bg-white rounded-md shadow-lg h-12 w-12">
<TouchableOpacity className="w-full h-full items-center justify-center">
<LucideIcon icon="Bot" size={26} clickable={false} strokeWidth={2} />
</TouchableOpacity>
</View>
<View className="flex-1 bg-white rounded-md shadow-lg h-12">
<TouchableOpacity
className="w-full h-full items-center justify-center flex flex-row"
onPress={() => {
setShowNavDrawer(true)
}}
>
<LucideIcon icon={currentNav.icon} size={20} strokeWidth={2} />
<Text className="font-semibold text-lg ml-2">{currentNav.label}</Text>
</TouchableOpacity>
</View>
<View className="bg-white rounded-md shadow-lg h-12 w-12">
<TouchableOpacity className="w-full h-full items-center justify-center" onPress={refreshPage}>
<LucideIcon icon="RefreshCcw" size={26} clickable={false} strokeWidth={2} />
</TouchableOpacity>
</View>
</View>
<ADrawer
visible={showNavDrawer}
height="60%"
title="菜单导航"
isCircle
hideModal={() => {
setShowNavDrawer(false)
}}
>
<Animated.ScrollView
ref={scrollableRef}
className="px-4 py-2 flex-1"
>
<Sortable.Grid
columnGap={16}
rowGap={16}
columns={3}
data={NAV_MENUS}
keyExtractor={item => item.path}
renderItem={renderNavItem}
scrollableRef={scrollableRef}
autoScrollActivationOffset={200}
/>
</Animated.ScrollView>
</ADrawer>
</View>
)
}
+15 -4
View File
@@ -1,11 +1,22 @@
import { useRouter } from 'expo-router'
import { Text, View } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { AButton } from '@/components/common/ao'
// 这个页面的作用是作为占位页,避免进入 (tabs) layout 时出现 404 页面。
// 如果想指定默认页面,可以通过 router.replace 或 TabTrigger 指向具体子页面。
export default function Index() {
const router = useRouter()
return (
<View>
<Text>Index</Text>
</View>
<SafeAreaView>
<View>
<AButton onPress={() => {
router.push('/money')
}}
>
测试
</AButton>
</View>
</SafeAreaView>
)
}