首页指南参考教程

截图

在本教程中,了解如何使用第三方库和 Expo Media Library 捕获屏幕截图。


在本章中,我们将学习如何使用第三方库截取屏幕截图并将其保存到设备的媒体库中。我们将使用以下库 react-native-view-shot(允许截屏)和 expo-media-library(允许访问设备的媒体库以保存图片)。

¥In this chapter, we will learn how to take a screenshot using a third-party library and save it on the device's media library. We'll use the following libraries react-native-view-shot that allows taking a screenshot, and expo-media-library that allows accessing a device's media library to save an image.

到目前为止,我们一直在使用一些第三方库,例如 react-native-gesture-handlerreact-native-reanimated,现在又使用了 react-native-view-shot。我们可以在 React Native 目录 上找到数百个其他第三方库。

¥So far, we have been using some third-party libraries such as react-native-gesture-handler, react-native-reanimated, and now react-native-view-shot. We can find hundreds of other third-party libraries on React Native Directory.

1

安装库

¥Install libraries

要安装这两个库,请运行以下命令:

¥To install both libraries, run the following commands:

Terminal
npx expo install react-native-view-shot expo-media-library

2

提示权限

¥Prompt for permissions

当创建需要访问潜在敏感信息(例如访问媒体库)的应用时,我们必须首先请求用户的许可。

¥When creating an app that requires access to potentially sensitive information, such as access to the media library, we must first request the user's permission.

expo-media-library 提供了一个授予 status 权限的 usePermissions() 钩子,以及一个在未授予权限时请求访问媒体库的 requestPermission() 方法。

¥expo-media-library provides a usePermissions() hook that gives the permission status, and a requestPermission() method to ask for access to the media library when permission is not granted.

最初,当应用第一次加载并且权限状态既不是授予也不是拒绝时,status 的值为 null。当请求权限时,用户可以授予权限或拒绝权限。我们可以添加一个条件来检查是否是 null,如果是,则触发 requestPermission() 方法。

¥Initially, when the app loads for the first time and the permission status is neither granted nor denied, the value of the status is null. When asked for permission, a user can either grant the permission or deny it. We can add a condition to check if it is null, and if it is, trigger the requestPermission() method.

<App> 组件中添加以下代码片段:

¥Add the following code snippet inside the <App> component:

App.js
import * as MediaLibrary from 'expo-media-library';

// ...rest of the code remains same

export default function App() {
  const [status, requestPermission] = MediaLibrary.usePermissions();
  // ...rest of the code remains same

  if (status === null) {
    requestPermission();
  }

  // ...rest of the code remains same
}

一旦获得许可,status 的值将更改为 granted

¥Once permission is given, the value of the status changes to granted.

3

选择一个库来截图

¥Picking a library to take screenshots

为了允许用户在应用内截取屏幕截图,我们将使用 react-native-view-shot。它允许将 <View> 捕获为图片。

¥To allow the user to take a screenshot within the app, we'll use react-native-view-shot. It allows capturing a <View> as an image.

让我们将其导入到 App.js 文件中:

¥Let's import it into App.js file:

App.js
import { captureRef } from 'react-native-view-shot';

4

创建一个 ref 来保存当前视图

¥Create a ref to save the current view

react-native-view-shot 库提供了一个名为 captureRef() 的方法,该方法可以捕获应用中 <View> 的屏幕截图并返回屏幕截图图片文件的 URI。

¥The react-native-view-shot library provides a method called captureRef() that captures a screenshot of a <View> in the app and returns the URI of the screenshot image file.

要捕获 <View>,请将 <ImageViewer><EmojiSticker> 组件封装在 <View> 内,然后传递对其的引用。使用 React 中的 useRef() 钩子,让我们在 <App> 中创建一个 imageRef 变量。

¥To capture a <View>, wrap the <ImageViewer> and <EmojiSticker> components inside a <View> and then pass a reference to it. Using the useRef() hook from React, let's create an imageRef variable inside <App>.

App.js
import { useState, useRef } from 'react';

export default function App() {
  const imageRef = useRef();

  // ...rest of the code remains same

  return (
    <GestureHandlerRootView style={styles.container}>
      <View style={styles.imageContainer}>
        <View ref={imageRef} collapsable={false}>
          <ImageViewer placeholderImageSource={PlaceholderImage} selectedImage={selectedImage} />
          {pickedEmoji && <EmojiSticker imageSize={40} stickerSource={pickedEmoji} />}
        </View>
      </View>
      

{/* ...rest of the code remains same */}


    </GestureHandlerRootView>
  );
}

在上面的代码片段中,collapsable 属性设置为 false,因为该 <View> 组件用于拍摄背景图片和表情符号贴纸的屏幕截图。应用屏幕的其余内容(例如按钮)不属于屏幕截图的一部分。

¥The collapsable prop is set to false in the above snippet because this <View> component is used to take a screenshot of the background image and the emoji sticker. The rest of the contents of the app screen (such as buttons) are not part of the screenshot.

5

捕获屏幕截图并保存

¥Capture a screenshot and save it

现在我们可以通过在 onSaveImageAsync() 函数内从 react-native-view-shot 调用 captureRef() 方法来捕获视图的屏幕截图。captureRef() 接受一个可选参数,我们可以在其中传递我们想要捕获屏幕截图的区域的 widthheight。我们可以在 库的文档 中阅读有关可用选项的更多信息。

¥Now we can capture a screenshot of the view by calling the captureRef() method from react-native-view-shot inside the onSaveImageAsync() function. captureRef() accepts an optional argument where we can pass the width and height of the area we'd like to capture a screenshot for. We can read more about available options in the library's documentation.

captureRef() 方法返回一个 promise,该 promise 通过捕获的屏幕截图的 URI 来实现。我们将此 URI 作为参数传递给 MediaLibrary.saveToLibraryAsync(),该 MediaLibrary.saveToLibraryAsync() 会将屏幕截图保存到设备的媒体库中。

¥The captureRef() method returns a promise that fulfills with the URI of the captured screenshot. We will pass this URI as a parameter to MediaLibrary.saveToLibraryAsync(), which will save the screenshot to the device's media library.

使用以下代码更新 onSaveImageAsync() 函数:

¥Update the onSaveImageAsync() function with the following code:

Take a screenshot
export default function App() {
  const onSaveImageAsync = async () => {
    try {
      const localUri = await captureRef(imageRef, {
        height: 440,
        quality: 1,
      });

      await MediaLibrary.saveToLibraryAsync(localUri);
      if (localUri) {
        alert("Saved!");
      }
    } catch (e) {
      console.log(e);
    }
  };
  // ...rest of the code remains same
}

现在,选择一张照片并添加贴纸。然后点击 "保存" 按钮。我们应该看到以下结果:

¥Now, choose a photo and add a sticker. Then tap the "Save" button. We should see the following result:

下一步

¥Next step

react-native-view-shotexpo-media-library 仅适用于 Android 和 iOS,但是,我们希望我们的应用也能在网络上运行。

¥The react-native-view-shot and expo-media-library work only on Android and iOS, however, we'd like our app to work on the web as well.

处理平台差异

在下一章中,我们将学习如何处理移动平台和网络平台之间的差异。

Expo 中文网 - 粤ICP备13048890号