React Native 全栈开发实战班 -原生功能集成之相机与图片

在移动应用中,相机功能图片选择 是非常常见的需求,用户可以通过相机拍照或从相册中选择图片。React Native 提供了多种方式来实现相机和图片选择功能,包括使用第三方库(如 react-native-image-picker)和调用原生模块。本章节将详细介绍如何使用 react-native-image-picker 库来实现相机和图片选择功能,包括基本用法、图片处理、权限管理以及自定义相机界面。


2.1 相机与图片选择概述

在移动应用中,相机和图片选择功能主要用于以下场景:

  • 用户头像设置: 用户可以通过相机拍照或从相册中选择图片作为头像。
  • 图片上传: 用户可以上传图片到服务器,如发布动态、分享照片等。
  • 扫描二维码: 通过相机扫描二维码或条形码。
  • 图片编辑: 用户可以对图片进行编辑,如裁剪、旋转、添加滤镜等。

React Native 提供了多种方式来实现相机和图片选择功能:

  1. 第三方库:react-native-image-picker, react-native-camera, react-native-image-crop-picker 等,提供了封装好的 API,可以快速实现相机和图片选择功能。
  2. 原生模块: 可以通过原生代码实现自定义相机和图片选择功能,适用于需要高度定制化的场景。

本章节将重点介绍如何使用 react-native-image-picker 库来实现相机和图片选择功能。


2.2 使用 react-native-image-picker

react-native-image-picker 是一个流行的第三方库,用于实现相机和图片选择功能,支持 iOS 和 Android 平台。

2.2.1 安装 react-native-image-picker
bash 复制代码
npm install react-native-image-picker

链接原生依赖(React Native 0.60 及以上版本自动链接):

bash 复制代码
cd ios
pod install
cd ..
2.2.2 配置权限

iOS:

Info.plist 文件中添加相机和相册权限说明。

xml 复制代码
<key>NSCameraUsageDescription</key>
<string>需要访问相机以拍摄照片</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择照片</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要保存照片到相册</string>

Android:

AndroidManifest.xml 文件中添加相机和存储权限。

xml 复制代码
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

注意: 对于 Android 6.0 及以上版本,还需要在代码中动态请求权限。

2.2.3 基本用法

请求相机或图片选择:

javascript 复制代码
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';

const handleChooseImage = () => {
  const options = {
    mediaType: 'photo',
    cameraType: 'back',
    maxWidth: 1080,
    maxHeight: 1080,
    quality: 0.8,
  };

  launchImageLibrary(options, (response) => {
    if (response.didCancel) {
      console.log('用户取消选择图片');
    } else if (response.errorCode) {
      console.error('图片选择错误:', response.errorMessage);
    } else {
      const asset = response.assets[0];
      console.log('选择的图片:', asset);
      // 处理选择的图片
    }
  });
};

const handleTakePhoto = () => {
  const options = {
    mediaType: 'photo',
    cameraType: 'back',
    saveToPhotos: true,
    maxWidth: 1080,
    maxHeight: 1080,
    quality: 0.8,
  };

  launchCamera(options, (response) => {
    if (response.didCancel) {
      console.log('用户取消拍照');
    } else if (response.errorCode) {
      console.error('拍照错误:', response.errorMessage);
    } else {
      const asset = response.assets[0];
      console.log('拍摄的图片:', asset);
      // 处理拍摄的图片
    }
  });
};

示例:

javascript 复制代码
import React from 'react';
import { View, Button, Image, StyleSheet, Alert } from 'react-native';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';

const CameraExample = () => {
  const handleTakePhoto = () => {
    const options = {
      mediaType: 'photo',
      cameraType: 'back',
      saveToPhotos: true,
      maxWidth: 1080,
      maxHeight: 1080,
      quality: 0.8,
    };

    launchCamera(options, (response) => {
      if (response.didCancel) {
        console.log('用户取消拍照');
      } else if (response.errorCode) {
        Alert.alert('拍照错误', response.errorMessage);
      } else {
        const asset = response.assets[0];
        console.log('拍摄的图片:', asset);
        // 处理拍摄的图片
      }
    });
  };

  const handleChooseImage = () => {
    const options = {
      mediaType: 'photo',
      maxWidth: 1080,
      maxHeight: 1080,
      quality: 0.8,
    };

    launchImageLibrary(options, (response) => {
      if (response.didCancel) {
        console.log('用户取消选择图片');
      } else if (response.errorCode) {
        Alert.alert('图片选择错误', response.errorMessage);
      } else {
        const asset = response.assets[0];
        console.log('选择的图片:', asset);
        // 处理选择的图片
      }
    });
  };

  return (
    <View style={styles.container}>
      <Button title="拍照" onPress={handleTakePhoto} />
      <Button title="选择图片" onPress={handleChooseImage} />
    </View>
  );
};

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

export default CameraExample;

解释:

  • launchCamera 方法: 打开相机进行拍照。
  • launchImageLibrary 方法: 打开相册选择图片。
  • options 参数: 配置相机或图片选择选项,如媒体类型、图片尺寸、质量等。
  • 回调函数: 处理用户取消、错误或选择结果。
2.2.4 处理选择的图片

react-native-image-picker 返回的图片信息包含图片的 URI、宽度、高度、大小等信息。可以使用 react-native-fast-image 或其他图片加载库来显示图片,并根据需要进行后续处理,如上传到服务器或保存到本地。

2.2.4.1 显示选择的图片

以下是如何使用 react-native-fast-image 显示用户选择的图片:

javascript 复制代码
import React from 'react';
import { View, Button, StyleSheet, Alert } from 'react-native';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import FastImage from 'react-native-fast-image';

const CameraExample = () => {
  const [image, setImage] = React.useState(null);

  const handleTakePhoto = () => {
    const options = {
      mediaType: 'photo',
      cameraType: 'back',
      saveToPhotos: true,
      maxWidth: 1080,
      maxHeight: 1080,
      quality: 0.8,
    };

    launchCamera(options, (response) => {
      if (response.didCancel) {
        console.log('用户取消拍照');
      } else if (response.errorCode) {
        Alert.alert('拍照错误', response.errorMessage);
      } else {
        const asset = response.assets[0];
        console.log('拍摄的图片:', asset);
        setImage(asset);
      }
    });
  };

  const handleChooseImage = () => {
    const options = {
      mediaType: 'photo',
      maxWidth: 1080,
      maxHeight: 1080,
      quality: 0.8,
    };

    launchImageLibrary(options, (response) => {
      if (response.didCancel) {
        console.log('用户取消选择图片');
      } else if (response.errorCode) {
        Alert.alert('图片选择错误', response.errorMessage);
      } else {
        const asset = response.assets[0];
        console.log('选择的图片:', asset);
        setImage(asset);
      }
    });
  };

  return (
    <View style={styles.container}>
      <View style={styles.buttonContainer}>
        <Button title="拍照" onPress={handleTakePhoto} />
        <Button title="选择图片" onPress={handleChooseImage} />
      </View>
      {image && (
        <View style={styles.imageContainer}>
          <FastImage
            source={{ uri: image.uri }}
            style={styles.image}
            resizeMode={FastImage.resizeMode.cover}
          />
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  buttonContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    width: '100%',
    marginBottom: 20,
  },
  imageContainer: {
    width: 300,
    height: 300,
    borderRadius: 10,
    overflow: 'hidden',
    marginBottom: 20,
  },
  image: {
    width: '100%',
    height: '100%',
  },
});

export default CameraExample;

解释:

  • setImage(asset): 将选择的图片信息存储在组件状态中。
  • FastImage: 使用 react-native-fast-image 显示图片,asset.uri 是图片的 URI。
  • resizeMode: 设置图片的缩放模式,如 cover, contain, stretch 等。
2.2.4.2 图片上传

用户选择或拍摄图片后,通常需要将图片上传到服务器。以下是如何实现图片上传的示例:

javascript 复制代码
import React from 'react';
import { View, Button, StyleSheet, Alert } from 'react-native';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import axios from 'axios';

const CameraExample = () => {
  const [image, setImage] = React.useState(null);

  const handleTakePhoto = () => {
    const options = {
      mediaType: 'photo',
      cameraType: 'back',
      saveToPhotos: true,
      maxWidth: 1080,
      maxHeight: 1080,
      quality: 0.8,
    };

    launchCamera(options, (response) => {
      if (response.didCancel) {
        console.log('用户取消拍照');
      } else if (response.errorCode) {
        Alert.alert('拍照错误', response.errorMessage);
      } else {
        const asset = response.assets[0];
        setImage(asset);
        uploadImage(asset);
      }
    });
  };

  const handleChooseImage = () => {
    const options = {
      mediaType: 'photo',
      maxWidth: 1080,
      maxHeight: 1080,
      quality: 0.8,
    };

    launchImageLibrary(options, (response) => {
      if (response.didCancel) {
        console.log('用户取消选择图片');
      } else if (response.errorCode) {
        Alert.alert('图片选择错误', response.errorMessage);
      } else {
        const asset = response.assets[0];
        setImage(asset);
        uploadImage(asset);
      }
    });
  };

  const uploadImage = async (asset) => {
    const formData = new FormData();
    formData.append('file', {
      uri: asset.uri,
      type: asset.type,
      name: asset.fileName || 'image.jpg',
    });

    try {
      const response = await axios.post('https://example.com/upload', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });
      Alert.alert('上传成功', `图片上传成功,图片ID: ${response.data.id}`);
    } catch (error) {
      Alert.alert('上传失败', '图片上传失败,请稍后重试');
    }
  };

  return (
    <View style={styles.container}>
      <View style={styles.buttonContainer}>
        <Button title="拍照" onPress={handleTakePhoto} />
        <Button title="选择图片" onPress={handleChooseImage} />
      </View>
      {image && (
        <View style={styles.imageContainer}>
          <FastImage
            source={{ uri: image.uri }}
            style={styles.image}
            resizeMode={FastImage.resizeMode.cover}
          />
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  buttonContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    width: '100%',
    marginBottom: 20,
  },
  imageContainer: {
    width: 300,
    height: 300,
    borderRadius: 10,
    overflow: 'hidden',
    marginBottom: 20,
  },
  image: {
    width: '100%',
    height: '100%',
  },
});

export default CameraExample;

解释:

  • uploadImage 函数: 使用 axios 发送 POST 请求,将图片上传到服务器。
  • FormData: 用于构建 multipart/form-data 请求体。
  • asset.uri: 图片的 URI,用于上传。
  • asset.type: 图片的 MIME 类型。
  • asset.fileName: 图片的文件名,如果未提供,则使用默认名称。
2.2.4.3 图片保存到相册

用户拍摄或选择的图片可以保存到相册中。

示例:

javascript 复制代码
import { writeToFile, copyFile, saveToLibrary } from 'react-native-image-picker';

const saveImageToAlbum = async (asset) => {
  try {
    const result = await saveToLibrary(asset.uri);
    Alert.alert('保存成功', '图片已保存到相册');
  } catch (error) {
    Alert.alert('保存失败', '图片保存到相册失败');
  }
};

作者简介

前腾讯电子签的前端负责人,现 whentimes tech CTO,专注于前端技术的大咖一枚!一路走来,从小屏到大屏,从 Web 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!

温馨提示:可搜老码小张公号联系导师

相关推荐
GISer_Jing3 小时前
React面试高频核心问题
前端·react.js·面试
Mrs_Lupin3 小时前
如何在react中使用react-monaco-editor渲染出一个编辑器
前端·react.js·编辑器
ZHOU_WUYI3 小时前
用 React18 构建Tic-Tac-Toe(井字棋)游戏
javascript·react.js·游戏
khatung7 小时前
React中事件绑定和Vue有什么区别?
前端·javascript·vue.js·vscode·react.js·前端框架
老码沉思录10 小时前
React Native 全栈开发实战班 - 原生功能集成之地理位置服务
javascript·react native·react.js
new出一个对象13 小时前
react+hook+vite项目使用eletron打包成桌面应用+可以热更新
前端·react.js·前端框架
新星_19 小时前
路由跳转和路由参数
react.js
老码沉思录21 小时前
React Native 全栈开发实战班 - 用户界面之手势系统应用
react native·react.js·ui
Foodie21 小时前
如何在原生鸿蒙中进行RN热加载
前端·react native·harmonyos