73 lines
2.2 KiB
TypeScript
73 lines
2.2 KiB
TypeScript
import { Ionicons } from '@expo/vector-icons'
|
|
import { usePathname, useRouter } from 'expo-router'
|
|
import { Image, Pressable, ScrollView, Text, View } from 'react-native'
|
|
import Animated, { SlideInRight } from 'react-native-reanimated'
|
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
|
|
|
export interface StepLayoutItem {
|
|
path: string // 步骤路径
|
|
title?: string // 步骤标题
|
|
onBack?: () => void // 可选的返回按钮回调
|
|
showHearder?: boolean // 是否显示 header,单独放在每个步骤中
|
|
headerRight?: React.ReactNode
|
|
}
|
|
|
|
interface StepLayoutProps {
|
|
steps: StepLayoutItem[] // 步骤列表
|
|
children: React.ReactNode // 子内容
|
|
showHearder?: boolean // 控制整体 header 是否显示
|
|
}
|
|
|
|
export default function StepLayout({ steps, children, showHearder = true }: StepLayoutProps) {
|
|
const router = useRouter()
|
|
const pathname = usePathname()
|
|
|
|
// 是否能返回
|
|
const canGoBack = router.canGoBack()
|
|
|
|
// 当前步骤
|
|
const currentStep = steps.find(step => step.path === pathname) ?? steps[0]
|
|
|
|
// 是否显示header
|
|
const headerVisible = showHearder !== false && currentStep.showHearder !== false
|
|
|
|
return (
|
|
<SafeAreaView style={{ flex: 1 }}>
|
|
<Animated.View
|
|
key={pathname}
|
|
entering={SlideInRight.duration(300)}
|
|
style={{ flex: 1 }}
|
|
>
|
|
{headerVisible && (
|
|
<View className="flex-row items-center h-12 px-2 ">
|
|
<Pressable
|
|
onPress={canGoBack ? (currentStep.onBack ?? (() => router.back())) : undefined}
|
|
style={{ opacity: canGoBack ? 1 : 0 }}
|
|
>
|
|
<Ionicons
|
|
name="arrow-back"
|
|
size={22}
|
|
/>
|
|
</Pressable>
|
|
|
|
<Text className="flex-1 text-center text-lg font-semibold">
|
|
{currentStep.title}
|
|
</Text>
|
|
|
|
<View className="h-full flex items-center justify-center">
|
|
{currentStep.headerRight ?? (
|
|
<Image
|
|
source={require('@/static/images/logo.png')}
|
|
style={{ width: 22, height: 22 }}
|
|
/>
|
|
)}
|
|
</View>
|
|
</View>
|
|
)}
|
|
|
|
<View style={{ flex: 1 }}>{children}</View>
|
|
</Animated.View>
|
|
</SafeAreaView>
|
|
)
|
|
}
|