在本教程中,了解如何使用第三方库和 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-handler
、react-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 nowreact-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:
-
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:
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:
import { captureRef } from 'react-native-view-shot';
4
¥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>
.
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()
接受一个可选参数,我们可以在其中传递我们想要捕获屏幕截图的区域的 width
和 height
。我们可以在 库的文档 中阅读有关可用选项的更多信息。
¥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:
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-shot
和 expo-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.
在下一章中,我们将学习如何处理移动平台和网络平台之间的差异。