当前位置:   article > 正文

React Native学习_react native 学习

react native 学习

React Native 学习

一、React Native 概述

React Native 让开发者使用 JavaScript 和 React 编写应用,利用相同的核心代码就可以创建 Web,iOS 和 Android 平台的原生应用。

React Native 的宗旨是,学习一次,高效编写跨平台原生应用。

官网:https://reactnative.cn/

1.1 React Native 特性

  1. React
  2. 原生
  3. 平台多样性:可以运行在iOS和Android

1.2 React Native 优点

  1. JavaScript
    完全采用JS语言。
  2. 跨平台
    一次编写,多处运行(iOS和Android)
  3. 有强大的社区

1.3 React Native 局限性

  1. 复杂的状态管理,页面切换
  2. 创建新的原生组件复杂

二、React Native 开发环境

  • 开发平台: Windows(Windows不能开发ios,需要Mac)
  • 目标平台: Android
  • 安装依赖:Node、Python2、JDK 和 Android Studio。

2.1 Android 开发环境

2.1.1 安装 Android Studio

国际版:下载
谷歌代理:下载

  1. android studio开发环境的搭建
  2. 安装完成Android studio后,需要配置 ANDROID_HOME 环境变量
2.1.2 安装 Android SDK

Android Studio 默认会安装最新版本的 Android SDK。目前编译 React Native 应用需要的是Android 10 (Q)版本的 SDK(注意 SDK 版本不等于终端系统版本,RN 目前支持 android 4.1 以上设备)。你可以在 Android Studio 的 SDK Manager 中选择安装各版本的 SDK。

你可以在 Android Studio 的欢迎界面中找到 SDK Manager。点击"Configure",然后就能看到"SDK Manager"。

SDK Manager 还可以在 Android Studio 的"Preferences"菜单中找到。具体路径是Appearance & Behavior → System Settings → Android SDK。

2.1.3 配置 ANDROID_HOME 环境变量

React Native 需要通过环境变量来了解你的 Android SDK 装在什么路径,从而正常进行编译。

打开控制面板 -> 系统和安全 -> 系统 -> 高级系统设置 -> 高级 -> 环境变量 -> 新建,创建一个名为ANDROID_HOME的环境变量(系统或用户变量均可),指向你的 Android SDK 所在的目录(具体的路径可能和下图不一致,请自行确认):
在这里插入图片描述

2.1.4 把一些工具目录添加到环境变量 Path

打开控制面板 -> 系统和安全 -> 系统 -> 高级系统设置 -> 高级 -> 环境变量,选中Path变量,然后点击编辑。点击新建然后把这些工具目录路径添加进去:platform-tools、emulator、tools、tools/bin

%ANDROID_HOME%\platform-tools
%ANDROID_HOME%\emulator
%ANDROID_HOME%\tools
%ANDROID_HOME%\tools\bin
  • 1
  • 2
  • 3
  • 4

2.2 创建新项目

如果你之前全局安装过旧的react-native-cli命令行工具,请使用npm uninstall -g react-native-cli卸载掉它以避免一些冲突。

使用 React Native 内建的命令行工具来创建一个名为"AwesomeProject"的新项目。这个命令行工具不需要安装,可以直接用 node 自带的npx命令来使用:

必须要看的注意事项一:请不要单独使用常见的关键字作为项目名(如 class, native, new, package
等等)。请不要使用与核心模块同名的项目名(如 react, react-native 等)。请不要在目录、文件名中使用中文、空格等特殊符号。

必须要看的注意事项二:请不要在某些权限敏感的目录例如 System32 目录中 init 项目!会有各种权限限制导致不能运行!

npx react-native init AwesomeProject
  • 1

如果你是想把 React Native 集成到现有的原生项目中,则步骤完全不同,请参考集成到现有原生应用。

2.2.1 [可选参数] 指定版本或项目模板

你可以使用–version参数(注意是两个杠)创建指定版本的项目。注意版本号必须精确到两个小数点。

npx react-native init AwesomeProject --version X.XX.X
  • 1

还可以使用–template来使用一些社区提供的模板,例如带有TypeScript配置的:

npx react-native init AwesomeTSProject --template react-native-template-typescript
  • 1

2.3 准备 Android 设备

你需要准备一台 Android 设备来运行 React Native Android 应用。这里所指的设备既可以是真机,也可以是模拟器。后面我们所有的文档除非特别说明,并不区分真机或者模拟器。Android 官方提供了名为 Android Virtual Device(简称 AVD)的模拟器。此外还有很多第三方提供的模拟器如GenymotionBlueStack 等。一般来说官方模拟器免费、功能完整,但性能较差。第三方模拟器性能较好,但可能需要付费,或带有广告。

2.3.1 使用 Android 真机

你也可以使用 Android 真机来代替模拟器进行开发,只需用 usb 数据线连接到电脑,然后遵照在设备上运行这篇文档的说明操作即可。

2.3.2 使用 Android 模拟器

你可以使用 Android Studio 打开项目下的"android"目录,然后可以使用"AVD Manager"来查看可用的虚拟设备,它的图标看起来像下面这样:
在这里插入图片描述
如果你刚刚才安装 Android Studio,那么可能需要先创建一个虚拟设备。点击"Create Virtual Device…",然后选择所需的设备类型并点击"Next",然后选择Q API Level 29 image.

译注:请不要轻易点击 Android Studio 中可能弹出的建议更新项目中某依赖项的建议,否则可能导致无法运行。

2.4 编译并运行 React Native 应用

确保你先运行了模拟器或者连接了真机,然后在你的项目目录中运行yarn android或者yarn react-native run-android

cd AwesomeProject
yarn android
# 或者
yarn react-native run-android
  • 1
  • 2
  • 3
  • 4

此命令会对项目的原生部分进行编译,同时在另外一个命令行中启动Metro服务对 js 代码进行实时打包处理(类似 webpack)。Metro服务也可以使用yarn start命令单独启动。

如果配置没有问题,你应该可以看到应用自动安装到设备上并开始运行。注意第一次运行时需要下载大量编译依赖,耗时可能数十分钟。此过程严重依赖稳定的代理软件,否则将频繁遭遇链接超时和断开,导致无法运行。

也可以尝试阿里云提供的maven 镜像,将android/build.gradle中的jcenter()google()分别替换为maven { url 'https://maven.aliyun.com/repository/jcenter' }maven { url 'https://maven.aliyun.com/repository/google' }(注意有多处需要替换)。

npx react-native run-android只是运行应用的方式之一。你也可以在 Android Studio 中直接运行应用。

译注:建议在run-android成功后再尝试使用 Android Studio 启动。请不要轻易点击 Android Studio 中可能弹出的建议更新项目中某依赖项的建议,否则可能导致无法运行。

如果你无法正常运行,遇到奇奇怪怪的红屏错误,先回头仔细对照文档检查,然后可以看看问题讨论区。不同时期不同版本可能会碰到不同的问题,我们会在论坛中及时解答更新。但请注意千万不要执行 bundle 命令,那样会导致代码完全无法刷新。

2.5 修改项目

现在你已经成功运行了项目,我们可以开始尝试动手改一改了:

  • 使用你喜欢的文本编辑器打开App.js并随便改上几行
  • 按两下 R 键,或是在开发者菜单中选择 Reload,就可以看到你的最新修改。

三、工程目录结构

react native 是构建在 android 和 ios 原生SDK之上的一个SDK
所以一个 react native 工程包括三部分内容:

  1. 原生 android 工程
  2. 原生 ios 工程
  3. react native 相关内容

我们通过一个新建的 react native 工程来介绍它的目录结构,首先命令行运行 react-native init ares 创建一个新的 react native 工程,目录结构如下

ares
 |-- android
 |-- ios
 |-- index.js
 |-- app.js
 |-- app.json
 |-- package.json
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

android:这个文件夹下是一个原生 android 工程 (一般不需要修改)
ios:这个文件夹下是一个原生 ios 工程(一般不需要修改)
package.json:react native 用的是 javascript 语言,所以使用了 npm 作为包管理,这个文件就是 npm 的包管理文件

3.1 index.js

index.js是项目的入口文件,一般初始化的加载和配置都放在这里

/**
 * @format
 */

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.2 App.js

App.js 是项目实际的React Native源码,主要存放项目的入口组件App

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
} from 'react-native';

import {
  Header,
  LearnMoreLinks,
  Colors,
  DebugInstructions,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          <Header />
          {global.HermesInternal == null ? null : (
            <View style={styles.engine}>
              <Text style={styles.footer}>Engine: Hermes</Text>
            </View>
          )}
          <View style={styles.body}>
            <View style={styles.sectionContainer}>
              <Text style={styles.sectionTitle}>Step One</Text>
              <Text style={styles.sectionDescription}>
                Edit <Text style={styles.highlight}>App.js</Text> to change this
                screen and then come back to see your edits.
              </Text>
            </View>
            <View style={styles.sectionContainer}>
              <Text style={styles.sectionTitle}>See Your Changes</Text>
              <Text style={styles.sectionDescription}>
                <ReloadInstructions />
              </Text>
            </View>
            <View style={styles.sectionContainer}>
              <Text style={styles.sectionTitle}>Debug</Text>
              <Text style={styles.sectionDescription}>
                <DebugInstructions />
              </Text>
            </View>
            <View style={styles.sectionContainer}>
              <Text style={styles.sectionTitle}>Learn More</Text>
              <Text style={styles.sectionDescription}>
                Read the docs to discover what to do next:
              </Text>
            </View>
            <LearnMoreLinks />
          </View>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: Colors.lighter,
  },
  engine: {
    position: 'absolute',
    right: 0,
  },
  body: {
    backgroundColor: Colors.white,
  },
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
    color: Colors.black,
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
    color: Colors.dark,
  },
  highlight: {
    fontWeight: '700',
  },
  footer: {
    color: Colors.dark,
    fontSize: 12,
    fontWeight: '600',
    padding: 4,
    paddingRight: 12,
    textAlign: 'right',
  },
});

export default App;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115

3.2 App.json

配置文件

四、React Native组件

4.1 Text 文本组件

显示文本内容的组件。相当于<p>

<Text>First part and </Text>
  • 1

4.2 View 视图组件

搭建用户界面的最基础组件。

作为创建 UI 时最基础的组件,View 是一个支持 Flexbox 布局、样式、触摸响应、和一些无障碍功能的容器。

相当于<div>

import React from "react";
import { View, Text } from "react-native";

const ViewBoxesWithColorAndText = () => {
  return (
    <View
      style={{
        flexDirection: "row",
        height: 100,
        padding: 20
      }}
    >
      <View style={{ backgroundColor: "blue", flex: 0.3 }} />
      <View style={{ backgroundColor: "red", flex: 0.5 }} />
      <Text>Hello World!</Text>
    </View>
  );
};

export default ViewBoxesWithColorAndText;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4.3 Image 图片组件

用于显示多种不同类型图片的 React 组件,包括网络图片、静态资源、临时的本地图片、以及本地磁盘上的图片(如相册)等。

import React from 'react';
import { View, Image, StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    paddingTop: 50,
  },
  stretch: {
    width: 50,
    height: 200,
    resizeMode: 'stretch',
  },
});

const DisplayAnImageWithStyle = () => {
  return (
    <View style={styles.container}>
      <Image
        style={styles.stretch}
        source={require('@expo/snack-static/react-native-logo.png')}
      />
    </View>
  );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

4.4 TextInput 输入文本

TextInput 是一个允许用户在应用中通过键盘输入文本的基本组件。本组件的属性提供了多种特性的配置,譬如自动完成、自动大小写、占位文字,以及多种不同的键盘类型(如纯数字键盘)等等。

最简单的用法就是丢一个TextInput到应用里,然后订阅它的onChangeText事件来读取用户的输入。注意,从 TextInput 里取值这就是目前唯一的做法!也就是使用在onChangeText中用setState把用户的输入写入到 state 中,然后在需要取值的地方从 this.state 中取出值。它还有一些其它的事件,譬如onSubmitEditingonFocus。一个简单的例子如下:

import React, { Component } from 'react';
import { TextInput } from 'react-native';

const UselessTextInput = () => {
  const [value, onChangeText] = React.useState('Useless Placeholder');

  return (
    <TextInput
      style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
      onChangeText={text => onChangeText(text)}
      value={value}
    />
  );
}

export default UselessTextInput;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

4.5 ScrollView 滚动视图

一个封装了平台的 ScrollView(滚动视图)的组件,同时还集成了触摸锁定的“响应者”系统。

记住 ScrollView 必须有一个确定的高度才能正常工作,因为它实际上所做的就是将一系列不确定高度的子组件装进一个确定高度的容器(通过滚动操作)。要给 ScrollView 一个确定的高度的话,要么直接给它设置高度(不建议),要么确定所有的父容器都有确定的高度。一般来说我们会给 ScrollView 设置flex: 1以使其自动填充父容器的空余空间,但前提条件是所有的父容器本身也设置了 flex 或者指定了高度,否则就会导致无法正常滚动,你可以使用元素查看器来查找具体哪一层高度不正确。

ScrollView 内部的其他响应者尚无法阻止 ScrollView 本身成为响应者。

ScrollViewFlatList应该如何选择?ScrollView 会简单粗暴地把所有子元素一次性全部渲染出来。其原理浅显易懂,使用上自然也最简单。然而这样简单的渲染逻辑自然带来了性能上的不足。想象一下你有一个特别长的列表需要显示,可能有好几屏的高度。创建和渲染那些屏幕以外的 JS 组件和原生视图,显然对于渲染性能和内存占用都是一种极大的拖累和浪费。

这就是为什么我们还有专门的FlatList组件。FlatList会惰性渲染子元素,只在它们将要出现在屏幕中时开始渲染。这种惰性渲染逻辑要复杂很多,因而 API 在使用上也更为繁琐。除非你要渲染的数据特别少,否则你都应该尽量使用FlatList,哪怕它们用起来更麻烦。

此外FlatList还可以方便地渲染行间分隔线,支持多列布局,无限滚动加载等等

import React from 'react';
import { StyleSheet, Text, SafeAreaView, ScrollView } from 'react-native';
import Constants from 'expo-constants';

const App = () => {
  return (
    <SafeAreaView style={styles.container}>
      <ScrollView style={styles.scrollView}>
        <Text style={styles.text}>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
          eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
          minim veniam, quis nostrud exercitation ullamco laboris nisi ut
          aliquip ex ea commodo consequat. Duis aute irure dolor in
          reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
          pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
          culpa qui officia deserunt mollit anim id est laborum.
        </Text>
      </ScrollView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: Constants.statusBarHeight,
  },
  scrollView: {
    backgroundColor: 'pink',
    marginHorizontal: 20,
  },
  text: {
    fontSize: 42,
  },
});

export default App;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

4.6 StyleSheet 样式对象

StyleSheet 提供了一种类似 CSS 样式表的抽象。

从代码质量角度:

  • 从渲染函数中移除具体的样式内容,可以使代码更清晰易读。
  • 给样式命名也可以对渲染函数中的组件增加语义化的描述。
import React from "react";
import { StyleSheet, Text, View } from "react-native";

const App = () => (
  <View style={styles.container}>
    <Text style={styles.title}>React Native</Text>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 24,
    backgroundColor: "#eaeaea"
  },
  title: {
    marginTop: 16,
    paddingVertical: 8,
    borderWidth: 4,
    borderColor: "#20232a",
    borderRadius: 6,
    backgroundColor: "#61dafb",
    color: "#20232a",
    textAlign: "center",
    fontSize: 30,
    fontWeight: "bold"
  }
});

export default App;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

4.7 Button 按钮组件

一个简单的跨平台的按钮组件。可以进行一些简单的定制。

这个组件的样式是固定的。所以如果它的外观并不怎么搭配你的设计,那你需要使用TouchableOpacity或是TouchableNativeFeedback组件来定制自己所需要的按钮,或者你也可以在 github.com 网站上搜索 ‘react native button’ 来看看社区其他人的作品。

import { Button } from 'react-native';
...

<Button
  onPress={onPressLearnMore}
  title="Learn More"
  color="#841584"
  accessibilityLabel="Learn more about this purple button"
/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.8 Switch 开关组件

跨平台通用的“开关”组件。

注意这是一个“受控组件”(controlled component)。你必须使用onValueChange回调来更新value属性以响应用户的操作。如果不更新value属性,组件只会按一开始给定的value值来渲染且保持不变,看上去就像完全点不动。

import React, { useState } from "react";
import { View, Switch, StyleSheet } from "react-native";

const App = () => {
  const [isEnabled, setIsEnabled] = useState(false);
  const toggleSwitch = () => setIsEnabled(previousState => !previousState);

  return (
    <View style={styles.container}>
      <Switch
        trackColor={{ false: "#767577", true: "#81b0ff" }}
        thumbColor={isEnabled ? "#f5dd4b" : "#f4f3f4"}
        ios_backgroundColor="#3e3e3e"
        onValueChange={toggleSwitch}
        value={isEnabled}
      />
    </View>
  );
}

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

export default App;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

4.9 FlatList 简单列表组件

高性能的简单列表组件,支持下面这些常用的功能:

  • 完全跨平台。
  • 支持水平布局模式。
  • 行组件显示或隐藏时可配置回调事件。
  • 支持单独的头部组件。
  • 支持单独的尾部组件。
  • 支持自定义行间分隔线。
  • 支持下拉刷新。
  • 支持上拉加载。
  • 支持跳转到指定行(ScrollToIndex)。
  • 支持多列布局。

如果需要分组/类/区(section),请使用<SectionList>.

import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar } from 'react-native';

const DATA = [
  {
    id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
    title: 'First Item',
  },
  {
    id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
    title: 'Second Item',
  },
  {
    id: '58694a0f-3da1-471f-bd96-145571e29d72',
    title: 'Third Item',
  },
];

const Item = ({ title }) => {
  return (
    <View style={styles.item}>
      <Text style={styles.title}>{title}</Text>
    </View>
  );
}

const App = () => {
  const renderItem = ({ item }) => (
    <Item title={item.title} />
  );

  return (
    <SafeAreaView style={styles.container}>
      <FlatList
        data={DATA}
        renderItem={renderItem}
        keyExtractor={item => item.id}
      />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: StatusBar.currentHeight || 0,
  },
  item: {
    backgroundColor: '#f9c2ff',
    padding: 20,
    marginVertical: 8,
    marginHorizontal: 16,
  },
  title: {
    fontSize: 32,
  },
});

export default App;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

4.10 ActivityIndicator loading组件

显示一个圆形的 loading 提示符号。

import React from "react";
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";

const App = () => (
  <View style={[styles.container, styles.horizontal]}>
    <ActivityIndicator />
    <ActivityIndicator size="large" />
    <ActivityIndicator size="small" color="#0000ff" />
    <ActivityIndicator size="large" color="#00ff00" />
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center"
  },
  horizontal: {
    flexDirection: "row",
    justifyContent: "space-around",
    padding: 10
  }
});

export default App;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

4.11 Alert 弹出框

启动一个提示对话框,包含对应的标题和信息。

你还可以指定一系列的按钮,点击对应的按钮会调用对应的 onPress 回调并且关闭提示框。默认情况下,对话框会仅有一个’确定’按钮。

本接口可以在 iOS 和 Android 上显示一个静态的提示框。只有 iOS 系统支持在提示框中加入文本框。

4.12 TouchableOpacity 封装视图

本组件用于封装视图,使其可以正确响应触摸操作。当按下的时候,封装的视图的不透明度会降低。

不透明度的变化是通过把子元素封装在一个Animated.View中来实现的,这个动画视图会被添加到视图层级中,少数情况下有可能会影响到布局。(译注:此组件与 TouchableHighlight 的区别在于并没有额外的颜色变化,更适于一般场景。)

示例:

import React, { useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";

const App = () => {
  const [count, setCount] = useState(0);
  const onPress = () => setCount(prevCount => prevCount + 1);

  return (
    <View style={styles.container}>
      <View style={styles.countContainer}>
        <Text>Count: {count}</Text>
      </View>
      <TouchableOpacity
        style={styles.button}
        onPress={onPress}
      >
        <Text>Press Here</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    paddingHorizontal: 10
  },
  button: {
    alignItems: "center",
    backgroundColor: "#DDDDDD",
    padding: 10
  },
  countContainer: {
    alignItems: "center",
    padding: 10
  }
});

export default App;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

4.12 Animated 动画

Animated库旨在使动画变得流畅,强大并易于构建和维护。Animated侧重于输入和输出之间的声明性关系,以及两者之间的可配置变换,此外还提供了简单的 start/stop方法来控制基于时间的动画执行。

创建动画最基本的工作流程是先创建一个 Animated.Value ,将它连接到动画组件的一个或多个样式属性,然后使用Animated.timing()通过动画效果展示数据的变化:

下面的例子演示了一个根据动画值fadeAnim来淡入淡出的视图:

import React, { useRef } from "react";
import { Animated, Text, View, StyleSheet, Button } from "react-native";

const App = () => {
  // fadeAnim will be used as the value for opacity. Initial Value: 0
  const fadeAnim = useRef(new Animated.Value(0)).current;

  const fadeIn = () => {
    // Will change fadeAnim value to 1 in 5 seconds
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 5000
    }).start();
  };

  const fadeOut = () => {
    // Will change fadeAnim value to 0 in 5 seconds
    Animated.timing(fadeAnim, {
      toValue: 0,
      duration: 5000
    }).start();
  };

  return (
    <View style={styles.container}>
      <Animated.View
        style={[
          styles.fadingContainer,
          {
            opacity: fadeAnim // Bind opacity to animated value
          }
        ]}
      >
        <Text style={styles.fadingText}>Fading View!</Text>
      </Animated.View>
      <View style={styles.buttonRow}>
        <Button title="Fade In" onPress={fadeIn} />
        <Button title="Fade Out" onPress={fadeOut} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center"
  },
  fadingContainer: {
    paddingVertical: 8,
    paddingHorizontal: 16,
    backgroundColor: "powderblue"
  },
  fadingText: {
    fontSize: 28,
    textAlign: "center",
    margin: 10
  },
  buttonRow: {
    flexDirection: "row",
    marginVertical: 16
  }
});

export default App;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
4.12.1 概览

Animated提供了两种类型的值:

  • Animated.Value()用于单个值
  • Animated.ValueXY()用于矢量值

Animated.Value可以绑定到样式或是其他属性上,也可以进行插值运算。单个Animated.Value可以用在任意多个属性上。

4.12.2 配置动画

Animated提供了三种动画类型。每种动画类型都提供了特定的函数曲线,用于控制动画值从初始值变化到最终值的变化过程:

  • Animated.decay()以指定的初始速度开始变化,然后变化速度越来越慢直至停下。
  • Animated.spring()提供了一个基础的弹簧物理模型.
  • Animated.timing()使用easing 函数让数值随时间动起来。

大多数情况下你应该使用timing()。默认情况下,它使用对称的 easeInOut 曲线,将对象逐渐加速到全速,然后通过逐渐减速停止结束。

4.12.3 使用动画

通过在动画上调用start()来启动动画。 start()可以传入一个回调函数,以便在动画完成时得到通知调用。如果动画运行正常,则完成回调收到的值为{finished:true}。如果动画是因为调用了stop()而结束(例如,因为它被手势或其他动画中断),则它会收到{finished:false}

Animated.timing({}).start(({ finished }) => {
  /* 动画完成的回调函数 */
});
  • 1
  • 2
  • 3
4.12.4 启用原生动画驱动

使用原生动画,我们会在开始动画之前将所有关于动画的内容发送到原生代码,从而使用原生代码在 UI 线程上执行动画,而不是通过对每一帧的桥接去执行动画。一旦动画开始,JS 线程就可以在不影响动画效果的情况下阻塞(去执行其他任务)掉了。

您可以通过在动画配置中指定useNativeDriver:true 来使用原生动画驱动。你可以在动画文档 中看到更详细的解释。

4.12.5 自定义动画组件

组件必须经过特殊处理才能用于动画。所谓的特殊处理主要是指把动画值绑定到属性上,并且在一帧帧执行动画时避免 react 重新渲染和重新调和的开销。此外还得在组件卸载时做一些清理工作,使得这些组件在使用时是安全的。

  • createAnimatedComponent()方法正是用来处理组件,使其可以用于动画。

Animated中默认导出了以下这些可以直接使用的动画组件,当然它们都是通过使用上面这个方法进行了封装:

  • Animated.Image
  • Animated.ScrollView
  • Animated.Text
  • Animated.View
4.12.6 组合动画

动画还可以使用组合函数以复杂的方式进行组合:

  • Animated.delay()在给定延迟后开始动画。
  • Animated.parallel()同时启动多个动画。
  • Animated.sequence()按顺序启动动画,等待每一个动画完成后再开始下一个动画。
  • Animated.stagger()按照给定的延时间隔,顺序并行的启动动画。

动画也可以通过将toValue设置为另一个动画的Animated.Value来简单的链接在一起。请参阅动画指南中的跟踪动态值值。

默认情况下,如果一个动画停止或中断,则组合中的所有其他动画也会停止。

4.12.7 合成动画值

你可以使用加减乘除以及取余等运算来把两个动画值合成为一个新的动画值:

  • Animated.add()
  • Animated.subtract()
  • Animated.divide()
  • Animated.modulo()
  • Animated.multiply()
4.12.8 插值

interpolate()函数允许输入范围映射到不同的输出范围。默认情况下,它将推断超出给定范围的曲线,但也可以限制输出值。它默认使用线性插值,但也支持缓动功能。

  • interpolate()

你可以在动画文档中了解到更多。

4.12.9 处理手势和其他事件

手势,如平移或滚动,以及其他事件可以使用Animated.event()直接映射到动画值。这是通过结构化映射语法完成的,以便可以从复杂的事件对象中提取值。第一层参数是一个数组,你可以在其中指定多个参数映射,这种映射可以是嵌套的对象。

  • Animated.event()

例如,在使用水平滚动手势时,为了将event.nativeEvent.contentOffset.x映射到scrollX(Animated.Value),您需要执行以下操作:

 onScroll={Animated.event(
   // scrollX = e.nativeEvent.contentOffset.x
   [{ nativeEvent: {
        contentOffset: {
          x: scrollX
        }
      }
    }]
 )}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.13 Dimensions

你可以用下面的方法来获取设备的宽高:

import { Dimensions } from "react-native";

const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
  • 1
  • 2
  • 3
  • 4

4.14 InteractionManager

InteractionManager是一个可以提升用户体验和交互效果的模块,它可以让一些任务在比较耗时的操作或者动画完成后执行,这样能够保证我们的js动画比较平滑的运行,比如导航跳转新页面。

五、React Native常用依赖

(1).下载某个库到本地

npm install ******
  • 1

(2).链接某个库到项目中

react-native link *****
  • 1

5.1 react-native-vector-icons

react-native的常用图标库

// 下载
yarn add react-native-vector-icons
// 引用
react-native link react-native-vector-icons
  • 1
  • 2
  • 3
  • 4

GitHub地址:https://github.com/oblador/react-native-vector-icons

图标参考地址:https://oblador.github.io/react-native-vector-icons/

//引入
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';

//应用
 <MaterialIcons  name={'home'} size={26} color=”#ff0000“/>
  • 1
  • 2
  • 3
  • 4
  • 5

5.2 react-navigation

react-native的规定的导航路由

yarn add react-navigation

yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
  • 1
  • 2
  • 3

需要将整个应用程序包装在中NavigationContainer。通常,您可以在条目文件中执行此操作,例如index.jsApp.js

import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';

export default function App() {
  return (
    <NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
  );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5.2.1 react-navigation/stack

React Navigation的堆栈导航器为您的应用程序提供了一种在屏幕之间转换和管理导航历史记录的方式。如果您的应用仅使用一个堆栈导航器,那么它在概念上类似于Web浏览器处理导航状态的方式-您的应用在用户与之交互时从导航堆栈中推送和弹出项目,这导致用户看到不同的屏幕。

yarn add react-navigation-stack @react-native-community/masked-view react-native-safe-area-context
  • 1

createStackNavigator是一个返回包含2个属性的对象的函数:ScreenNavigator。它们都是用于配置导航器的React组件。Navigator应包含Screen元素作为其子元素,以定义路由的配置。

NavigationContainer是管理我们的导航树并包含导航状态的组件。该组件必须包装所有导航器结构。通常,我们会在应用程序的根目录下渲染此组件,该组件通常是从导出的组件App.js

5.3 react-native-scrollable-tab-view

react-native-scrollable-tab-view是一个滑动tab组件,可在tab之间进行切换显示内容

1、安装依赖

cnpm install --save react-native-scrollable-tab-view
  • 1

2、引入组件

import ScrollableTabView,{DefaultTabBar,ScrollableTabBar}  from 'react-native-scrollable-tab-view';
  • 1

3、组件使用

ScrollableTabBar :Tab可以超过屏幕范围,滚动可以显示
DefaultTabBar : Tab会平分在水平方向的空间

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/564169
推荐阅读
相关标签
  

闽ICP备14008679号