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.
12 KiB
12 KiB
02-导航和布局设计
目标
配置 React Navigation 导航系统,实现 Tab 导航和 Stack 导航。
UI 设计参考
参考设计稿:
files/ui/首页.png
底部 Tab 导航规范
| Tab | 图标 | 文字 |
|---|---|---|
| 首页 | 房屋图标 home |
首页 |
| AI问答 | 对话气泡 chat-processing |
AI问答 |
| 体质分析 | 心电图 chart-line-variant |
体质分析 |
| 我的 | 用户图标 account |
我的 |
Tab 样式规范
const tabBarOptions = {
activeTintColor: '#10B981', // 选中颜色
inactiveTintColor: '#9CA3AF', // 未选中颜色
style: {
height: 60,
paddingBottom: 8,
paddingTop: 8,
backgroundColor: '#FFFFFF',
borderTopWidth: 1,
borderTopColor: '#E5E7EB',
},
labelStyle: {
fontSize: 12,
},
}
前置要求
- 项目结构已初始化
- React Navigation 已安装
- 模拟数据服务已创建
实施步骤
步骤 1:创建导航类型定义
创建 src/navigation/types.ts:
import type { NativeStackNavigationProp } from '@react-navigation/native-stack'
import type { BottomTabNavigationProp } from '@react-navigation/bottom-tabs'
import type { CompositeNavigationProp, RouteProp } from '@react-navigation/native'
// Root Stack
export type RootStackParamList = {
Auth: undefined
Main: undefined
}
// Auth Stack
export type AuthStackParamList = {
Login: undefined
}
// Main Tab
export type MainTabParamList = {
HomeTab: undefined
ChatTab: undefined
ConstitutionTab: undefined
ProfileTab: undefined
}
// Home Stack
export type HomeStackParamList = {
Home: undefined
}
// Chat Stack
export type ChatStackParamList = {
ChatList: undefined
ChatDetail: { id: string }
}
// Constitution Stack
export type ConstitutionStackParamList = {
ConstitutionHome: undefined
ConstitutionQuestions: undefined
ConstitutionResult: undefined
}
// Profile Stack
export type ProfileStackParamList = {
ProfileHome: undefined
HealthRecord: undefined
}
// Navigation Props
export type RootNavigationProp = NativeStackNavigationProp<RootStackParamList>
export type ChatNavigationProp = CompositeNavigationProp<
NativeStackNavigationProp<ChatStackParamList>,
BottomTabNavigationProp<MainTabParamList>
>
// Route Props
export type ChatDetailRouteProp = RouteProp<ChatStackParamList, 'ChatDetail'>
步骤 2:创建认证状态 Store
创建 src/stores/useAuthStore.ts:
import { create } from 'zustand'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { User } from '../types'
interface AuthState {
isLoggedIn: boolean
user: User | null
login: (user: User) => void
logout: () => void
}
export const useAuthStore = create<AuthState>((set) => ({
isLoggedIn: false,
user: null,
login: (user) => {
AsyncStorage.setItem('user', JSON.stringify(user))
set({ isLoggedIn: true, user })
},
logout: () => {
AsyncStorage.removeItem('user')
set({ isLoggedIn: false, user: null })
},
}))
步骤 3:创建主 Tab 导航
创建 src/navigation/MainTabNavigator.tsx:
import React from 'react'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
import type { MainTabParamList } from './types'
import HomeNavigator from './HomeNavigator'
import ChatNavigator from './ChatNavigator'
import ConstitutionNavigator from './ConstitutionNavigator'
import ProfileNavigator from './ProfileNavigator'
const Tab = createBottomTabNavigator<MainTabParamList>()
const MainTabNavigator = () => {
return (
<Tab.Navigator
screenOptions={{
headerShown: false,
tabBarActiveTintColor: '#10B981',
tabBarInactiveTintColor: '#9CA3AF',
tabBarStyle: {
height: 60,
paddingBottom: 8,
paddingTop: 8,
},
tabBarLabelStyle: {
fontSize: 12,
},
}}
>
<Tab.Screen
name="HomeTab"
component={HomeNavigator}
options={{
tabBarLabel: '首页',
tabBarIcon: ({ color, size }) => (
<Icon name="home" size={size} color={color} />
),
}}
/>
<Tab.Screen
name="ChatTab"
component={ChatNavigator}
options={{
tabBarLabel: 'AI问答',
tabBarIcon: ({ color, size }) => (
<Icon name="chat-processing" size={size} color={color} />
),
}}
/>
<Tab.Screen
name="ConstitutionTab"
component={ConstitutionNavigator}
options={{
tabBarLabel: '体质分析',
tabBarIcon: ({ color, size }) => (
<Icon name="chart-line-variant" size={size} color={color} />
),
}}
/>
<Tab.Screen
name="ProfileTab"
component={ProfileNavigator}
options={{
tabBarLabel: '我的',
tabBarIcon: ({ color, size }) => (
<Icon name="account" size={size} color={color} />
),
}}
/>
</Tab.Navigator>
)
}
export default MainTabNavigator
步骤 4:创建子导航器
创建 src/navigation/HomeNavigator.tsx:
import React from 'react'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import type { HomeStackParamList } from './types'
import HomeScreen from '../screens/home/HomeScreen'
const Stack = createNativeStackNavigator<HomeStackParamList>()
const HomeNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: '健康AI助手',
headerStyle: { backgroundColor: '#10B981' },
headerTintColor: '#fff',
}}
/>
</Stack.Navigator>
)
}
export default HomeNavigator
创建 src/navigation/ChatNavigator.tsx:
import React from 'react'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import type { ChatStackParamList } from './types'
import ChatListScreen from '../screens/chat/ChatListScreen'
import ChatDetailScreen from '../screens/chat/ChatDetailScreen'
const Stack = createNativeStackNavigator<ChatStackParamList>()
const ChatNavigator = () => {
return (
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: '#10B981' },
headerTintColor: '#fff',
}}
>
<Stack.Screen
name="ChatList"
component={ChatListScreen}
options={{ title: 'AI问答' }}
/>
<Stack.Screen
name="ChatDetail"
component={ChatDetailScreen}
options={{ title: '健康咨询' }}
/>
</Stack.Navigator>
)
}
export default ChatNavigator
创建 src/navigation/ConstitutionNavigator.tsx:
import React from 'react'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import type { ConstitutionStackParamList } from './types'
import ConstitutionHomeScreen from '../screens/constitution/ConstitutionHomeScreen'
import ConstitutionQuestionsScreen from '../screens/constitution/ConstitutionQuestionsScreen'
import ConstitutionResultScreen from '../screens/constitution/ConstitutionResultScreen'
const Stack = createNativeStackNavigator<ConstitutionStackParamList>()
const ConstitutionNavigator = () => {
return (
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: '#10B981' },
headerTintColor: '#fff',
}}
>
<Stack.Screen
name="ConstitutionHome"
component={ConstitutionHomeScreen}
options={{ title: '体质分析' }}
/>
<Stack.Screen
name="ConstitutionQuestions"
component={ConstitutionQuestionsScreen}
options={{ title: '体质问卷' }}
/>
<Stack.Screen
name="ConstitutionResult"
component={ConstitutionResultScreen}
options={{ title: '测评结果' }}
/>
</Stack.Navigator>
)
}
export default ConstitutionNavigator
创建 src/navigation/ProfileNavigator.tsx:
import React from 'react'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import type { ProfileStackParamList } from './types'
import ProfileHomeScreen from '../screens/profile/ProfileHomeScreen'
import HealthRecordScreen from '../screens/profile/HealthRecordScreen'
const Stack = createNativeStackNavigator<ProfileStackParamList>()
const ProfileNavigator = () => {
return (
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: '#10B981' },
headerTintColor: '#fff',
}}
>
<Stack.Screen
name="ProfileHome"
component={ProfileHomeScreen}
options={{ title: '我的' }}
/>
<Stack.Screen
name="HealthRecord"
component={HealthRecordScreen}
options={{ title: '健康档案' }}
/>
</Stack.Navigator>
)
}
export default ProfileNavigator
步骤 5:创建根导航器
创建 src/navigation/RootNavigator.tsx:
import React from 'react'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { useAuthStore } from '../stores/useAuthStore'
import type { RootStackParamList } from './types'
import LoginScreen from '../screens/auth/LoginScreen'
import MainTabNavigator from './MainTabNavigator'
const Stack = createNativeStackNavigator<RootStackParamList>()
const RootNavigator = () => {
const { isLoggedIn } = useAuthStore()
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
{!isLoggedIn ? (
<Stack.Screen name="Auth" component={LoginScreen} />
) : (
<Stack.Screen name="Main" component={MainTabNavigator} />
)}
</Stack.Navigator>
)
}
export default RootNavigator
步骤 6:更新 App.tsx
import React from 'react'
import { NavigationContainer } from '@react-navigation/native'
import { PaperProvider } from 'react-native-paper'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import RootNavigator from './src/navigation/RootNavigator'
import { theme } from './src/theme'
const App = () => {
return (
<SafeAreaProvider>
<PaperProvider theme={theme}>
<NavigationContainer>
<RootNavigator />
</NavigationContainer>
</PaperProvider>
</SafeAreaProvider>
)
}
export default App
导航结构
RootNavigator
├── LoginScreen(未登录)
└── MainTabNavigator(已登录)
├── HomeTab
│ └── Home
├── ChatTab
│ ├── ChatList
│ └── ChatDetail
├── ConstitutionTab
│ ├── ConstitutionHome
│ ├── ConstitutionQuestions
│ └── ConstitutionResult
└── ProfileTab
├── ProfileHome
└── HealthRecord
需要创建的文件清单
| 文件路径 | 说明 |
|---|---|
src/navigation/types.ts |
导航类型定义 |
src/stores/useAuthStore.ts |
认证状态 |
src/navigation/RootNavigator.tsx |
根导航 |
src/navigation/MainTabNavigator.tsx |
Tab 导航 |
src/navigation/HomeNavigator.tsx |
首页导航 |
src/navigation/ChatNavigator.tsx |
对话导航 |
src/navigation/ConstitutionNavigator.tsx |
体质导航 |
src/navigation/ProfileNavigator.tsx |
个人导航 |
验收标准
- 导航结构配置正确
- Tab 导航显示正常
- Stack 导航跳转正常
- 登录状态切换导航正常
预计耗时
30-40 分钟
下一步
完成后进入 02-APP原型开发/03-登录页面.md