healthapp
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

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