u
This commit is contained in:
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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user