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 小时前
state和ref
前端·javascript·react.js
Hi202402178 小时前
使用 Apollo TransformWrapper 生成相机到各坐标系的变换矩阵
数码相机·线性代数·矩阵·自动驾驶·apollo
前端啵啵猪9 小时前
useCallback 和 useMemo,什么时候用才是有效的?
前端·react.js
海海思思10 小时前
Redux Toolkit的前世今生:从繁琐到简洁的状态管理革命
react.js·redux
小爱同学_10 小时前
React知识:useState和useRef的使用
前端·react.js
索马里亚纳海参炒贩11 小时前
useCallback useMemo memo 三个区别和作用
前端·react native
nenchoumi311913 小时前
全网首发!Realsense 全新 D555 相机开箱记录与 D435i、L515、D456 横向测评!
数码相机·计算机视觉·机器人·ros·realsense
知识分享小能手14 小时前
React学习教程,从入门到精通, React 新创建组件语法知识点及案例代码(11)
前端·javascript·学习·react.js·架构·前端框架·react
举个栗子dhy17 小时前
解决在父元素上同时使用 onMouseEnter和 onMouseLeave时导致下拉菜单无法正常展开或者提前收起问题
前端·javascript·react.js