Files
workspace/code/base-project/base-app/src/components/custom/StepLayout.tsx
T
2025-11-05 15:57:11 +08:00

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>
)
}