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

news2025/1/15 10:51:20

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

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

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

目录标题

      • 〇 简介路由和导航
          • 路由(Routing)
          • React Navigation
          • 设置导航
          • React Navigation 学习前提条件
            • 1 React Native Express (第1至4节)
            • 2 React的主要概念
            • 3 React Hooks
            • 4 React Context (高级)
      • 一 简介
          • 1 安装组件库
          • 2 安装依赖
          • 3 链接
      • 二 基础组件
        • 1 添加头部组件 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1c1d340b6d024a1bb5247832a80b2c07.png)
        • 2 添加导航容器
      • 三 几种基本导航类型
          • 1. 堆栈导航(Stack Navigation)
          • 2. 底部标签导航(Bottom Tab Navigation)
          • 3. 抽屉导航(Drawer Navigation)
          • 4. Material顶部标签导航(Material Top Tab Navigation)

〇 简介路由和导航

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

路由(Routing)

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

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

React Navigation

在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 学习前提条件

在开始学习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)。

1. 堆栈导航(Stack Navigation)

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

主要特性

  • 页面间的无缝过渡。
  • 可以自定义过渡动画。
  • 支持页面传参。
 npm install @react-navigation/stack

// 引入所需的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')}
      />

在这里插入图片描述

2. 底部标签导航(Bottom Tab Navigation)

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

主要特性
适合快速切换不同视图的应用。
可定制标签样式和动画。

npm install @react-navigation/bottom-tabs

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


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

主要特点
跨平台支持:这些图标可以在 iOS 和 Android 平台上使用,且看起来一致。
自定义和扩展性:你可以轻松地调整图标的大小、颜色和样式,使其适应你的应用设计。
丰富的图标资源:Ionicons 包括了数百个图标,涵盖了大多数常见的 UI 设计需求。

在这里插入图片描述

/* 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,
  },
});

3. 抽屉导航(Drawer Navigation)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

主要特性
可以包含用户账户信息、链接列表等。
支持手势操作。

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 需要这个插件来正确转换工作单元代码。配置应如下所示:

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

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

yarn start --reset-cache

在项目目录内执行:

npx react-native start --reset-cache

在这里插入图片描述

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

下面带注释

/* 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,
  },
});

4. Material顶部标签导航(Material Top Tab Navigation)

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

主要特性
支持滑动操作切换标签。
可定制动画和样式。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1628626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript-事件监听、事件对象与事件流

事件监听 什么是事件什么是事件监听&#xff1f;事件监听三要素 事件监听L0 绑定L2 绑定区别vue绑定 事件类型鼠标事件键盘事件焦点事件文本事件 什么是事件对象获取事件对象环境对象回调函数事件流事件捕获事件冒泡阻止冒泡 解绑事件两种注册事件的区别事件委托 什么是事件 事…

「笔试刷题」:孩子们的游戏(圆圈中最后剩下的数)

一、题目 描述 每年六一儿童节&#xff0c;牛客都会准备一些小礼物和小游戏去看望孤儿院的孩子们。其中&#xff0c;有个游戏是这样的&#xff1a;首先&#xff0c;让 n 个小朋友们围成一个大圈&#xff0c;小朋友们的编号是0~n-1。然后&#xff0c;随机指定一个数 m &#xf…

敏捷之Scrum开发

目录 一、什么是 Scrum 1.1 Scrum 的定义 二、Scrum 迭代开发过程 2.1 迭代开发过程说明 2.1.1 开发方法 2.1.1.1 增量模型 2.1.1.1.1 定义 2.1.1.1.2 模型方法说明 2.1.1.2 迭代模型 2.1.1.2.1 定义 2.1.1.2.2 模型方法说明 2.1.2 迭代过程 2.1.2.1 产品需求Produ…

GPU服务器和普通服务器有何区别?

众所周知&#xff0c;服务器是网络中的重要设备&#xff0c;要接受少至几十人、多至成千上万人的访问&#xff0c;因此对服务器具有大数据量的快速吞吐、超强的稳定性、长时间运行等严格要求。 GPU服务器和普通服务器的主要区别在于硬件配置和适用场景&#xff0c;特别是处理器…

STM32修改主频的方法

大家都知道STM32F103C8T6的主频是72M&#xff0c;那怎么样才能在程序中获得这个主频的值呢&#xff1f;怎么样才能更改主频的值呢&#xff1f; 如图找到主频的变量&#xff0c;然后显示这个变量就是显示主频了。 #include "stm32f10x.h" // Device…

【图解计算机网络】简单易懂的https原理解析

简单易懂的https原理解析 https与http的区别混合加密对称加密非对称加密混合加密解析混合加密问题 摘要算法数字证书数字证书原理为什么通过CA证书可以解决中间人攻击的问题呢&#xff1f; https握手流程 https与http的区别 http是明文传输的&#xff0c;非常不安全&#xff0…

Java混淆的重要性

在软件开发领域&#xff0c;安全性与代码保护一直是备受关注的问题。特别是在Java这样的跨平台语言中&#xff0c;保护源代码的机密性和完整性显得尤为重要。Java混淆作为一种代码保护技术&#xff0c;其在现代软件开发中的地位日益凸显。本文将详细探讨Java混淆的重要性&#…

Java上传文件并存储到MySQL数据库

Java上传文件并存储到MySQL数据库实现过程&#xff1a; 第一步创建接口层 /** *文件接口层 */RestControllerRequestMapping("/file")public class FileController { //引用文件业务层 Resource private FileService fileService; /** *上传文件接…

基于51单片机的智能红外遥控电源电压调节系统设计

基于51单片机的智能红外遥控电源电压调节系统设计 摘要&#xff1a;随着科技的发展&#xff0c;电源电压调节系统在各种电子设备中发挥着越来越重要的作用。本文设计了一种基于51单片机的智能红外遥控电源电压调节系统&#xff0c;该系统能够通过红外遥控器实现对电源电压的快…

网络安全实训Day23

网络空间安全实训-渗透测试 文件上传攻击 定义 将Webshell文件上传到网站服务器上&#xff0c;从而获得网站整台服务器控制权限的攻击方式 Webshell 一种以网页形式存在的命令行执行环境&#xff0c;又称网页木马 分类 一句话木马 只有一行代码&#xff0c;功能强大&#xff…

ssm智能停车场管理系统

视频演示效果: SSMvue智能停车场 摘 要 本论文主要论述了如何使用JAVA语言开发一个智能停车场管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述智能停车…

【匹配】匈牙利匹配算法

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 匈牙利匹配算法 1. 正文 1.1 基础概念 二分图 顶点分为两个集合&#xff0c;集合间顶点相连&#xff0c;集合内点不相连 匹配 一个匹配就是一个边的…

ZYNQ之嵌入式开发04——自定义IP核实现呼吸灯、固化程序

文章目录 自定义IP核——呼吸灯实验固化程序 自定义IP核——呼吸灯实验 Xilinx官方提供了很多IP核&#xff0c;在Vivado的IP Catalog中可以查看这些IP核&#xff0c;在构建自己复杂的系统时&#xff0c;只使用Xilinx官方的免费IP核一般满足不了设计的要求&#xff0c;因此很多…

【Linux进程】守护进程

【Linux进程】守护进程 目录 【Linux进程】守护进程守护进程守护进程概念进程组和会话的概念 系统的守护进程函数 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2024.4.27 前言&#xff1a;本篇博客将会介绍守护进程&#xff0c;以及进程组和会话的概念&#xff0c;如何变成…

我教你如何可翻页电子画册

​电子画册是一种创新的方式&#xff0c;可以将传统的纸质画册转化为数字化的形式&#xff0c;并且具备翻页的功能。它不仅可以提供更好的阅读体验&#xff0c;还可以方便地分享给他人。 1.选择制作工具&#xff1a; 有许多在线平台和软件可以帮助你制作电子画册&#xff0c;比…

Qt6找不到Bluetooth蓝牙组件

图文解释来了&#xff01;调试了一下午。 错误如图&#xff1a; Failed to find required Qt component "Bluetooth" 解决方法&#xff1a; 找到安装QT安装包下的MaintenanceTool.exe&#xff0c;双击打开 打开后&#xff0c;找到这个Qt Connectivity&#xff0c;…

ChatGPT有记忆了?!持久记忆(Memory)功能详细解读和教程!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

【个人博客搭建】(11)swagger添加jwt信息

这个主要是为了方便使用swagger时&#xff0c;能更好的带入我们的token。 ps&#xff1a;如果使用其他第三方api工具&#xff08;apipost、postman等&#xff09;则不需要。 &#xff08;当然&#xff0c;不用不能没有&#xff0c;是吧&#xff09; 1、在AddSwaggerGen内添加…

阿里开源截止目前为止参数规模最大的Qwen1.5-110B模型:MMLU评测接近Llama-3-70B,略超Mixtral-8×22B!

本文原文来自DataLearnerAI官方网站&#xff1a;阿里开源截止目前为止参数规模最大的Qwen1.5-110B模型&#xff1a;MMLU评测接近Llama-3-70B&#xff0c;略超Mixtral-822B&#xff01; | 数据学习者官方网站(Datalearner)https://www.datalearner.com/blog/1051714140775766 Qw…

Android使用AlertDialog实现弹出菜单

最近又开始捣鼓APP&#xff0c;许多api , class都忘记怎么用了&#xff0c;楼下使用AlertDialog实现个弹出菜单&#xff0c;结果直接crash&#xff0c;查了半天&#xff0c;终于即将&#xff0c;记录一下…… 1 实现代码 AlertDialog.Builder mBuilder new AlertDialog.Builde…