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 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!

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

相关推荐
傻小胖8 分钟前
React 脚手架使用指南
前端·react.js·前端框架
若川1 小时前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
资源补给站10 小时前
大恒相机开发(2)—Python软触发调用采集图像
开发语言·python·数码相机
真的很上进11 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
我是前端小学生13 小时前
React Native 中的 View 组件:全面解析
react native
wakangda21 小时前
React Native 集成 iOS 原生功能
react native·ios·cocoa
SuperHeroWu721 小时前
【HarmonyOS】HarmonyOS和React Native混合开发 (一)之环境安装
react native·harmonyos·鸿蒙·开发环境·环境安装·rn·混合开发
wakangda1 天前
React Native 集成原生Android功能
javascript·react native·react.js
秃头女孩y1 天前
【React中最优雅的异步请求】
javascript·vue.js·react.js
前端小小王1 天前
React Hooks
前端·javascript·react.js