【iOS开发】(五)react Native路由和导航20240421-22

【iOS开发】(五)react Native 路由和导航Navigation 20240421

在(一)(二)中我们 Reactnative搭建了开发环境、学习了 基础语法、状态管理,JSX、组件、状态和生命周期以及样式布局等。

在(三)(四) React native 我们介绍了 RN中的基础组件和第三方组件。

今天我们来学习基础语法中最后一块重要的内容,路由和导航。

目录标题

      • [〇 简介路由和导航](#〇 简介路由和导航)
          • 路由(Routing)
          • [React Navigation](#React Navigation)
          • 设置导航
          • [React Navigation 学习前提条件](#React Navigation 学习前提条件)
            • [1 React Native Express (第1至4节)](#1 React Native Express (第1至4节))
            • [2 React的主要概念](#2 React的主要概念)
            • [3 React Hooks](#3 React Hooks)
            • [4 React Context (高级)](#4 React Context (高级))
      • [一 简介](#一 简介)
          • [1 安装组件库](#1 安装组件库)
          • [2 安装依赖](#2 安装依赖)
          • [3 链接](#3 链接)
      • [二 基础组件](#二 基础组件)
      • [三 几种基本导航类型](#三 几种基本导航类型)
          • [1. 堆栈导航(Stack Navigation)](#1. 堆栈导航(Stack Navigation))
          • [2. 底部标签导航(Bottom Tab Navigation)](#2. 底部标签导航(Bottom Tab Navigation))
          • [3. 抽屉导航(Drawer Navigation)](#3. 抽屉导航(Drawer Navigation))
          • [4. Material顶部标签导航(Material Top Tab Navigation)](#4. Material顶部标签导航(Material Top Tab Navigation))

〇 简介路由和导航

路由和导航是Web和移动应用中至关重要的概念,它们用于指导用户在应用的不同部分和页面之间移动。

路由(Routing)

路由通常指的是确定一个用户请求应该如何被处理的过程。在Web应用中,路由涉及到解析URL,并根据这个URL映射到相应的页面或视图上。对于复杂的前端Web应用,通常会使用客户端路由来在不同视图间切换而无需从服务器重新加载页面。

在React Native中,路由和导航指的是用户在 不同屏幕或视图(通常称为"路由") 之间移动的方式。由于React Native是一个用于构建移动应用的框架,所以它的路由和导航是专门为触摸界面设计的,能够处理各种手势操作和过渡动画。

在React Native中,最流行的路由和导航库是React Navigation。它提供了多种导航方法:

  • 堆栈导航(Stack Navigator):
    管理一系列屏幕,用户可以在屏幕间前进和后退。
    使用push和pop操作来管理屏幕堆栈。
  • 底部标签导航(Bottom Tab Navigator):
    在屏幕底部显示标签栏,用户可以通过点击不同的标签来切换视图。
  • 抽屉导航(Drawer Navigator):
    提供从屏幕边缘滑入的导航菜单,类似于抽屉式的交互模式。
  • 顶部标签导航(Material Top Tabs Navigator):
    在屏幕顶部显示标签栏,用户可以通过滑动或点击标签来切换视图。
    这种风格常见于Android应用,使用了Material Design规范。
设置导航

要在React Native应用中设置导航,通常需要以下步骤:

安装React Navigation库及其依赖。

创建导航器(例如堆栈导航器或标签导航器)并定义路由。

使用NavigationContainer组件包裹应用的根组件。

学习本部分内容,建议查漏补缺:

在开始学习React Navigation之前,确保你已经熟悉以下关键技术和概念。如果你已经有JavaScript、React和React Native的基础,你将能够快速上手React Navigation。如果你对这些还不够熟悉,建议先学习以下内容:

1 React Native Express (第1至4节)
  • 一个快速入门React Native的学习平台。
  • 包含设置开发环境、理解基础组件、状态管理、样式和布局等核心概念。
  • 推荐给刚开始接触React Native的开发者。
2 React的主要概念
  • React官方文档的主要概念部分提供了全面的介绍。
  • 学习内容包括JSX、组件、props、state、事件处理等基础知识。
  • 强烈建议理解组件生命周期和组件间的数据流。
3 React Hooks
  • React Hooks是React 16.8引入的新特性,允许在函数组件中使用state和其他React特性。
  • 重要的Hooks包括useState, useEffect, useContext等。
  • React官方文档提供了详细的Hooks介绍和使用指南。
4 React Context (高级)
  • Context API允许组件跨层级直接共享状态,而不是通过props链式传递。
  • 对于主题、用户认证、应用偏好等跨组件共享的数据非常有用。
  • 需要注意的是,不当使用可能会导致组件难以维护,因此建议在真正需要全局状态管理时才使用。

在了解了这些基础知识后,你将更好地准备学习React Navigation,并在你的React Native应用中实现复杂的导航逻辑。

一 简介

在React Native中,路由和导航是管理应用中页面或视图之间切换的关键技术。要实现这一功能,通常会使用第三方库,因为React Native本身并不包括内建的导航系统。React Navigation:流行的路由和导航库的组件。。

这是React Native中最流行的导航库组件之一。

它支持堆栈导航、标签导航、抽屉导航等多种导航方式。

React Navigation易于使用,并且高度可定制,支持屏幕转换动画、传递参数到不同屏幕等功能。

1 安装组件库
npm install @react-navigation/native
2 安装依赖
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

这个命令会安装以下库:

  • react-native-reanimated:提供更为强大和灵活的动画库,用于创建复杂的动画和交互。
  • react-native-gesture-handler:一个用来处理触摸手势的库,它优化了触摸响应的性能和体验。
  • react-native-screens:利用原生平台的视图容器来优化内存使用和性能
  • react-native-safe-area-context:提供了一个安全区域的上下文,可以用来适配屏幕的安全区域,避免界面元素与设备特定的屏幕部位(如刘海、圆角等)冲突。
  • @react-native-community/masked-view:一个实现遮罩视图的库,可以用来在视图上创建遮罩效果。

确保React Native环境已经配置好,并且这些库与React Native版本兼容。在安装这些库后,可能需要链接某些库(如果你的React Native版本低于0.60),并对Android和iOS项目进行必要的配置,以确保一切正常工作。

3 链接
  • RN0.60 后安卓环境自动链接路由(Android 无需任何操作 )

  • ios下需要手动链接路由

    npx pod-install ios

二 基础组件

1 添加头部组件

首先,需要在应用的最顶部导入react-native-gesture-handler。这是因为react-native-gesture-handler提供了一个可以更精细地控制手势和触摸事件的系统,这对于实现流畅的导航动画和用户体验至关重要。

导入这个模块的正确位置是在应用的入口文件中,通常是index.js或App.js。这需要放在任何其他代码之前,因为它要尽可能早地在应用中设置好手势处理的环境。

这里是一个示例代码:

// index.js 或 App.js
import 'react-native-gesture-handler'; // 这行代码要放在最上面
// 其他的导入和代码...
2 添加导航容器

导航容器(NavigationContainer)是一个组件,它管理着你的应用状态和导航树结构,它必须包裹在你的应用外层,这样React Navigation库才能正常工作。它通常也是放在index.js或App.js文件中。

这里是如何包裹你的应用:

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import MyStack from './MyStack'; // 假设你有一个堆栈导航器设置在另一个文件中

const App = () => {
  return (
    <NavigationContainer>
      <MyStack />
    </NavigationContainer>
  );
};

export default App;

在上面的例子中,MyStack是一个假设的组件,它表示你的应用的堆栈导航。当然,你可以根据需要替换为你自己的导航结构,无论是底部标签导航、抽屉导航还是其他类型的导航。

确保你的整个应用都被NavigationContainer包裹着,这样无论你在应用中的哪个部分,React Navigation都能访问当前的导航状态。这是启用导航功能的必备结构。

三 几种基本导航类型

详细介绍React Navigation中的几种基本导航类型:堆栈导航(Stack Navigation)、底部标签导航(Bottom Tab Navigation)、抽屉导航(Drawer Navigation)以及Material顶部标签导航(Material Top Tab Navigation)。

堆栈导航允许应用维护一个页面的堆栈,类似于导航控制器。新的页面可以放到堆栈的顶部,并且可以返回到之前的页面。

主要特性

  • 页面间的无缝过渡。

  • 可以自定义过渡动画。

  • 支持页面传参。

    npm install @react-navigation/stack

javascript 复制代码
// 引入所需的React Native组件
import {
  Text, // 用于显示文本
  StyleSheet, // 用于定义组件的样式
  View, // 用作容器,可以包裹其他组件
  Button, // 显示一个可点击的按钮
  TouchableOpacity, // 一个包装器,可以包含其他组件,并使它们可触摸
  Alert, // 提供弹出警告对话框的功能
} from 'react-native';
import React, {Component} from 'react'; // 引入React以及类组件的基类Component
import {createStackNavigator} from '@react-navigation/stack'; // 引入创建堆栈导航器的函数
import { NavigationContainer } from '@react-navigation/native'; // 引入包裹导航器的容器组件

// 定义HomeScreen组件,表示主屏幕
function HomeScreen(prop) {
  // 展示基本信息,并提供一个按钮用于跳转到NewsScreen页面
  return (
    <View style={styles.container}>
      <Text style={styles.text}>HomeScreen</Text>
      <Button
        title={'跳到新闻页面'}
        onPress={() => prop.navigation.navigate('News')} // 使用navigate方法跳转到指定的路由(页面)
      />
    </View>
  );
}

// 定义NewsScreen组件,表示新闻页面
function NewsScreen(prop) {
  // 类似HomeScreen,展示基本信息,并提供一个按钮用于返回HomeScreen页面
  return (
    <View style={styles.container}>
      <Text style={styles.text}>NewsScreen</Text>
      <Button
        title={'跳转到Home页面'}
        onPress={() => prop.navigation.navigate('Home')} // 使用navigate方法跳转回HomeScreen
      />
    </View>
  );
}

const Stack = createStackNavigator(); // 创建一个堆栈导航器

// 定义Index类组件,作为应用的主组件
export default class Index extends Component {
  render() {
    // 使用NavigationContainer包裹导航器,确保导航状态正确管理
    return (
      <NavigationContainer> 
        
        <Stack.Navigator  
        initialRouteName='News'   screenOptions={{headerShown:true}}>

          <Stack.Screen
            name="Home" // 路由名称
            component={HomeScreen} // 与此路由关联的组件
            options={{
              title: '首页', // 设置屏幕顶部导航条的标题
              headerStyle: {
                backgroundColor: 'tomato', // 自定义标题栏背景颜色
              },
              headerRight: () => (
                // 添加一个按钮在标题栏右侧
                <TouchableOpacity onPress={() => Alert.alert('Hello')}>
                  <Text style={{ marginRight: 15 }}>Hello</Text>
                </TouchableOpacity>
              ),
            }}
          />
          <Stack.Screen name="News" component={NewsScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}

// 定义组件的样式
const styles = StyleSheet.create({
  container: {
    flex: 1, // flex: 1 使组件填满父容器的全部空间
    justifyContent: 'center', // 垂直居中显示
    alignItems: 'center', // 水平居中显示
  },
  text: {
    fontSize: 40, // 设置字体大小
  },
});

简介版

import { Text, StyleSheet, View, Button } from 'react-native';
import React, { Component } from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';

function HomeScreen(props) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Home Screen</Text>
      <Button 
        title="跳转到新闻"
        onPress={() => props.navigation.navigate('News')}
      />
    </View>
  );
}

function NewsScreen(props) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>News Screen</Text>
      <Button
        title="跳转到home主页"
        onPress={() => props.navigation.navigate('Home')}
      />
    </View>
  );
}

const Stack = createStackNavigator();

export default class Index extends Component {
  render() {
    return (
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen
            name='Home'
            component={HomeScreen}
          />
          <Stack.Screen
            name='News'
            component={NewsScreen}
          />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  text: {
    fontSize: 40,
  }
});

关于navigation对象和navigate方法:

navigation是React Navigation传递给每个屏幕组件的对象,它包含了控制导航的多种方法。

navigate方法用于触发导航到应用中的其他屏幕,通常接受目标屏幕的名字作为参数,也可以传递附加数据。

<Stack.Screen />组件:

<Stack.Screen />是一个React Navigation的组件,用于在堆栈导航器中注册一个新的屏幕。

name属性定义了屏幕的标识符,用于编程时引用和导航到这个屏幕。

component属性指定当导航到这个屏幕时应该渲染哪个组件。

此代码中,

  <Text style={[styles.text]}>Home Screen</Text>
      <Button 

        title={'跳转到新闻'}


        /**
         * 
        
        prop:
        prop 是 React 中组件接收的参数,它包含了传递给组件的所有属性。
        在使用 React Navigation 时,所有通过导航器(Navigator)加载的组件会自动接收一个 navigation 属性。这个属性包含了一系列方法,用来编程式地控制导航行为,如跳转、后退等。
        
        prop.navigation:
        navigation 是 React Navigation 传递给每个屏幕组件的对象,包含了多种导航相关的方法和属性。通过这个对象,你可以控制应用的导航状态,执行如跳转、返回、参数传递等操作。
        navigate:
        navigate 是 navigation 对象中的一个方法,用于触发导航到应用中的其他屏幕。这个方法接受一个参数,通常是目标屏幕的名字(在代码中为 'News'),这个名字是在你设置导航器时定义的屏幕名。
        navigate 方法还可以接收第二个可选参数,用于传递数据到目标屏幕。这可以使你在不同的页面间传递需要的信息。
        简单来说,当你在 HomeScreen 组件中点击按钮时,onPress 事件会触发 prop.navigation.navigate('News') 调用,这会告诉 React Navigation 切换视图到 NewsScreen 组件。
         */

        //此处写一个具体的事件 onPress ,里面是回调函数   ()=>  
        // 可以通过传过来的参数 prop来跳转
        //prop 里面有 
        onPress={() => props.navigation.navigate('News')}
      />

底部标签导航在屏幕底部显示多个标签,用户可以切换不同的视图或页面。

主要特性

适合快速切换不同视图的应用。

可定制标签样式和动画。

npm install @react-navigation/bottom-tabs

我们要使用icon图标 所以也装一下

npm 复制代码

react-native-vector-icons/Ionicons 是一个在 React Native 应用中广泛使用的库,它提供了一套丰富的矢量图标,可以轻松地在移动应用中使用。这些图标是基于矢量技术的,意味着它们在不同的屏幕分辨率和尺寸上都可以保持清晰。Ionicons 是这个库中的一个图标集,它包括了一系列优雅的、常用的图标,适用于多种用户界面设计。

主要特点

跨平台支持:这些图标可以在 iOS 和 Android 平台上使用,且看起来一致。

自定义和扩展性:你可以轻松地调整图标的大小、颜色和样式,使其适应你的应用设计。

丰富的图标资源:Ionicons 包括了数百个图标,涵盖了大多数常见的 UI 设计需求。

javascript 复制代码
/* eslint-disable react/no-unstable-nested-components */
import {Text, StyleSheet, View, Button} from 'react-native';
import React, {Component} from 'react';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
import { NavigationContainer } from '@react-navigation/native';

function HomeScreen(props) {  // 更正 prop 为 props,这是常规的参数命名约定
  return (
    <View style={styles.container}>
      <Text style={styles.text}>HomeScreen</Text>
      <Button
        title="跳到新闻页面"  // 保持引号的一致性
        onPress={() => props.navigation.navigate('News')}
      />
    </View>
  );
}

function NewsScreen(props) {  // 更正 prop 为 props
  return (
    <View style={styles.container}>
      <Text style={styles.text}>NewsScreen</Text>
      <Button
        title="跳转到Home页面"  // 保持引号的一致性
        onPress={() => props.navigation.navigate('Home')}
      />
    </View>
  );
}

const Tab = createBottomTabNavigator();

export default class Index extends Component {
  render() {
    return (
      <NavigationContainer>
        <Tab.Navigator
          screenOptions={({route}) => ({
            tabBarIcon: ({focused, color, size}) => {
              let iconName;
              if (route.name === 'Home') {
                iconName = focused ? 'add-circle' : 'add-circle-outline';
              } else if (route.name === 'News') {
                iconName = focused ? 'person' : 'person-outline';
              }
              return <Icon name={iconName} size={size} color={color} />;
            },
            tabBarActiveTintColor: 'tomato',  // 将 tabBarOptions 的设置迁移到 screenOptions 中
            tabBarInactiveTintColor: 'gray',
          })}
        >
          <Tab.Screen name="Home" component={HomeScreen} />
          <Tab.Screen name="News" component={NewsScreen} />
        </Tab.Navigator>
      </NavigationContainer>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 40,
  },
});
/* eslint-disable react/no-unstable-nested-components */
import {Text, StyleSheet, View, Button} from 'react-native';
import React, {Component} from 'react';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
import { NavigationContainer } from '@react-navigation/native';

function HomeScreen(props) {  // 更正 prop 为 props,这是常规的参数命名约定
  return (
    <View style={styles.container}>
      <Text style={styles.text}>HomeScreen</Text>
      <Button
        title="跳到新闻页面"  // 保持引号的一致性
        onPress={() => props.navigation.navigate('News')}
      />
    </View>
  );
}

function NewsScreen(props) {  // 更正 prop 为 props
  return (
    <View style={styles.container}>
      <Text style={styles.text}>NewsScreen</Text>
      <Button
        title="跳转到Home页面"  // 保持引号的一致性
        onPress={() => props.navigation.navigate('Home')}
      />
    </View>
  );
}

const Tab = createBottomTabNavigator();

export default class Index extends Component {
  render() {
    return (
      <NavigationContainer>
        <Tab.Navigator
          screenOptions={({route}) => ({
            tabBarIcon: ({focused, color, size}) => {
              let iconName;
              if (route.name === 'Home') {
                iconName = focused ? 'add-circle' : 'add-circle-outline';
              } else if (route.name === 'News') {
                iconName = focused ? 'person' : 'person-outline';
              }
              return <Icon name={iconName} size={size} color={color} />;
            },
            tabBarActiveTintColor: 'tomato',  // 将 tabBarOptions 的设置迁移到 screenOptions 中
            tabBarInactiveTintColor: 'gray',
          })}
        >
          <Tab.Screen name="Home" component={HomeScreen} />
          <Tab.Screen name="News" component={NewsScreen} />
        </Tab.Navigator>
      </NavigationContainer>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 40,
  },
});

抽屉导航通过滑动或点击图标来展开一个从页面边缘滑出的导航面板。

主要特性

可以包含用户账户信息、链接列表等。

支持手势操作。

Uncaught Error [Reanimated] Failed to create a worklet. See https://docs.swmansion.com/react-native-reanimated/docsguides/troubleshooting#failed-to-create-a-workletfor more details. Source

看起来您遇到的错误与react-native-reanimated的工作单元(worklet)有关。这个问题通常发生在Reanimated的工作单元无法正确初始化时。下面是一些可能的解决步骤:

解决步骤

确认Reanimated插件:

确保babel.config.js中正确添加了react-native-reanimated/plugin。这一步是必要的,因为Reanimated 2 需要这个插件来正确转换工作单元代码。配置应如下所示:

javascript 复制代码
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'],
};

如果已经配置了插件,试着再次清理缓存:

yarn start --reset-cache

在项目目录内执行:

npx react-native start --reset-cache
javascript 复制代码
import React, { Component } from 'react';
import { Text, StyleSheet, View, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import Icon from 'react-native-vector-icons/Ionicons';

function HomeScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>HomeScreen</Text>
      <Button
        title="Open Drawer"
        onPress={() => navigation.openDrawer()}
      />
      <Button
        title="Toggle Drawer"
        onPress={() => navigation.toggleDrawer()}
      />
    </View>
  );
}

function NewsScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>NewsScreen</Text>
      <Button
        title="Open Drawer"
        onPress={() => navigation.openDrawer()}
      />
      <Button
        title="跳转到Home页面"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

const Drawer = createDrawerNavigator();

function Index() {
  return (
    <Drawer.Navigator
      screenOptions={{
        drawerStyle: {
            backgroundColor: '#c6cbef',
            width: 180,
          },
          drawerPosition: 'right',
          drawerType: 'slide',
          drawerActiveTintColor: 'red',
          drawerItemStyle: {
            marginVertical: 20,
          },
      }}>
      <Drawer.Screen
        options={{
          title: '首页',
          drawerIcon: ({ focused, color, size }) => (
            <Icon name={focused ? 'home' : 'home-outline'} size={size} color={color} />
          ),
        }}
        name="Home"
        component={HomeScreen}
      />
      <Drawer.Screen
        options={{
          title: '新闻',
          drawerIcon: ({ focused, color, size }) => (
            <Icon name={focused ? 'person' : 'person-outline'} size={size} color={color} />
          ),
        }}
        name="News"
        component={NewsScreen}
      />
    </Drawer.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Index />
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 40,
  },
});

下面带注释

javascript 复制代码
/* eslint-disable react/no-unstable-nested-components */
import {Text, StyleSheet, View, Button} from 'react-native';
import React, {Component} from 'react';
import {createDrawerNavigator} from '@react-navigation/drawer';
import Icon from 'react-native-vector-icons/Ionicons';
import { NavigationContainer } from '@react-navigation/native';

/**
 * drawer编译错误[Reanimated] `valueUnpacker` is not a worklet, js engine: hermes
 * 的解决办法 参考文章https://blog.csdn.net/lxyoucan/article/details/121851577
 * 第一步
 * 修改配置文件babel.config.js(在项目根目录)并增加plugins: ['react-native-reanimated/plugin'],
 * 示例:
 * module.exports = {
 *   presets: ['module:metro-react-native-babel-preset'],
 *   plugins: ['react-native-reanimated/plugin'],
 * };
 * 第二步
 * cmd命令行进入项目根目录,然后执行
 * yarn start --reset-cache
 * 清除缓存
 * 以上执行完毕之后
 * 关掉模拟器重新执行项目即可正常
 */

function HomeScreen(prop) {
  // 跳转方法prop.navigation.navigate参数是路由名称也就是Stack.Screen name
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>HomeScreen</Text>
      <Button
        title={'Open Drawer'}
        onPress={() => prop.navigation.openDrawer()}
      />
      <Button
        title={'Toggle Drawer'}
        onPress={() => prop.navigation.toggleDrawer()}
      />
    </View>
  );
}

function NewsScreen(prop) {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>NewsScreen</Text>
      <Button
        title={'Open Drawer'}
        onPress={() => prop.navigation.openDrawer()}
      />
      <Button
        title={'跳转到Home页面'}
        onPress={() => prop.navigation.navigate('Home')}
      />
    </View>
  );
}

const Drawer = createDrawerNavigator();

export default class Index extends Component {
  render() {
    return (
      <NavigationContainer>

      <Drawer.Navigator
        // 这里新版本和教程有变化,新版本属性写在screenOptions里
        screenOptions={{
          drawerStyle: {
            backgroundColor: '#c6cbef',
            width: 180,
          },
          drawerPosition: 'right', // 控制菜单从左left或者右right弹出
          drawerType: 'slide', // 菜单的滑动形式
          drawerActiveTintColor: 'red', // 当前激活的菜单颜色
          // 设置菜单项的样式
          drawerItemStyle: {
            marginVertical: 20,
          },
        }}>
        <Drawer.Screen
          options={{
            title: '首页', // 自定义当前项的标题
            drawerIcon: ({focused, color, size}) => {
              let iconName = '';
              iconName = focused ? 'home' : 'home-outline';
              return <Icon name={iconName} size={size} color={color} />;
            },
          }}
          name="Home"
          component={HomeScreen}
        />
        <Drawer.Screen
          options={{
            title: '新闻', // 自定义当前项的标题
            drawerIcon: ({focused, color, size}) => {
              let iconName = '';
              iconName = focused ? 'person' : 'person-outline';
              return <Icon name={iconName} size={size} color={color} />;
            },
          }}
          name="News"
          component={NewsScreen}
        />
      </Drawer.Navigator>
      </NavigationContainer>

    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 40,
  },
});

使用Material Design指南来实现顶部标签的滑动切换界面。

主要特性

支持滑动操作切换标签。

可定制动画和样式。

javascript 复制代码
import {Text, StyleSheet, View} from 'react-native';
import React, {Component} from 'react';
import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
import { NavigationContainer } from '@react-navigation/native';
import PagerView from 'react-native-pager-view';

function OrderunpayScreen() {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>待付款</Text>
    </View>
  );
}

function OrderPaidScreen() {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>待发货</Text>
    </View>
  );
}

function OrderSentScreen() {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>待收货</Text>
    </View>
  );
}

function OrderFinishScreen() {
  return (
    <View style={[styles.container]}>
      <Text style={[styles.text]}>待评价</Text>
    </View>
  );
}

const MTab = createMaterialTopTabNavigator();

export default class index extends Component {
  render() {
    // tabBarPosition 导航条的位置top|bottom默认是top
    return (

      <NavigationContainer>
      <MTab.Navigator
        tabBarPosition="bottom"
        screenOptions={{
          // tabBar的整体样式
          tabBarStyle: {
            borderWidth: 1,
            borderColor: 'grey',
          },
          // 标签样式
          tabBarLabelStyle: {
            fontSize: 20,
          },
          tabBarActiveTintColor: 'red', // 当前标签页标签激活时的颜色
          tabBarInactiveTintColor: '#666', // 当前标签页标签未激活时的颜色
          tabBarShowIcon: true, //是否显示图标
        }}>
        <MTab.Screen
          name="OrderUnpay"
          component={OrderunpayScreen}
          options={{
            title: '待付款',
            tabBarIcon: ({focused, color}) => {
              return <Icon name="hammer-outline" color={color} size={20} />;
            },
          }}
        />
        <MTab.Screen
          name="OrderPaid"
          component={OrderPaidScreen}
          options={{
            title: '待发货',
            tabBarIcon: ({focused, color}) => {
              return (
                <Icon
                  name="arrow-redo-circle-outline"
                  color={color}
                  size={20}
                />
              );
            },
          }}
        />
        <MTab.Screen
          name="OrderSent"
          component={OrderSentScreen}
          options={{
            title: '待收货',
            tabBarIcon: ({focused, color}) => {
              return <Icon name="arrow-redo-outline" color={color} size={20} />;
            },
          }}
        />
        <MTab.Screen
          name="OrderFinish"
          component={OrderFinishScreen}
          options={{
            title: '待评价',
            tabBarIcon: ({focused, color}) => {
              return (
                <Icon
                  name="chatbubble-ellipses-outline"
                  color={color}
                  size={20}
                />
              );
            },
          }}
        />
      </MTab.Navigator>
      </NavigationContainer>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 40,
  },
});
相关推荐
独上归州2 小时前
Vue与React的Suspense组件对比
前端·vue.js·react.js·suspense
安和昂3 小时前
【iOS】bug调试技巧
ios·bug·cocoa
emperinter3 小时前
WordCloudStudio Now Supports AliPay for Subscriptions !
人工智能·macos·ios·信息可视化·中文分词
秦时明月之君临天下4 小时前
React和Next.js的相关内容
前端·javascript·react.js
AirDroid_cn4 小时前
iPhone或iPad接收的文件怎么找?怎样删除?
ios·iphone·ipad·文件传输
米奇妙妙wuu4 小时前
React中 setState 是同步的还是异步的?调和阶段 setState 干了什么?
前端·javascript·react.js
李刚大人4 小时前
react-amap海量点优化
前端·react.js·前端框架
Swift社区10 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
#摩斯先生10 小时前
Swift从0开始学习 对象和类 day3
ios·xcode·swift
没头脑的ht10 小时前
Swift内存访问冲突
开发语言·ios·swift