react-native-vision-camera核心功能解析:拍照录像全攻略

react-native-vision-camera核心功能解析:拍照录像全攻略

【免费下载链接】react-native-vision-camera 📸 A powerful, high-performance React Native Camera library. 【免费下载链接】react-native-vision-camera 项目地址: https://gitcode.com/GitHub_Trending/re/react-native-vision-camera

引言:重新定义React Native相机体验

你还在为React Native项目中的相机功能卡顿、画质差、API复杂而烦恼吗?作为开发者,我们深知在移动应用中实现专业级相机功能的痛点——系统相机API碎片化、性能损耗严重、自定义功能受限。react-native-vision-camera作为一款高性能相机库,通过深度整合原生相机框架与React Native架构,提供了接近原生的拍摄体验。本文将从实战角度全面解析其拍照录像核心功能,带你掌握从基础配置到高级优化的全流程解决方案。

读完本文你将获得:

  • 拍照录像功能的完整实现方案
  • 设备适配与性能优化的实战技巧
  • 错误处理与边缘情况的解决方案
  • 10+可直接复用的代码片段
  • 基于真实设备测试的参数配置指南

核心功能架构概览

react-native-vision-camera采用模块化设计,核心功能围绕Camera组件展开,通过分层抽象实现对原生相机能力的高效调用。其架构可分为以下层次:

mermaid

核心API调用流程如下:

mermaid

环境配置与基础集成

前置依赖与权限配置

react-native-vision-camera需要React Native 0.60+环境,且必须配置相机和麦克风权限:

Android配置android/app/src/main/AndroidManifest.xml):

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

iOS配置ios/项目名/Info.plist):

<key>NSCameraUsageDescription</key>
<string>需要访问相机拍摄照片和视频</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要访问麦克风录制视频声音</string>

安装与项目集成

通过npm或yarn安装:

npm install react-native-vision-camera
# 或
yarn add react-native-vision-camera

iOS需额外安装pod依赖:

cd ios && pod install && cd ..

拍照功能全解析

基础拍照流程实现

拍照功能通过takePhoto方法实现,基本流程包含设备选择、权限检查和拍照调用三个步骤:

import React, { useRef, useState } from 'react';
import { View, StyleSheet, Button } from 'react-native';
import { Camera, useCameraDevice, useCameraPermission } from 'react-native-vision-camera';

export function PhotoCaptureExample() {
  const camera = useRef<Camera>(null);
  const [photo, setPhoto] = useState(null);
  const permission = useCameraPermission();
  const device = useCameraDevice('back');

  // 检查权限
  if (permission.status !== 'granted') {
    return <View><Text>请授予相机权限</Text></View>;
  }

  if (!device) {
    return <View><Text>未找到相机设备</Text></View>;
  }

  const takePhoto = async () => {
    if (!camera.current) return;
    
    try {
      const photoFile = await camera.current.takePhoto({
        flash: 'auto',
        enableAutoRedEyeReduction: true,
      });
      setPhoto(photoFile);
      console.log('照片保存路径:', photoFile.path);
    } catch (e) {
      console.error('拍照失败:', e);
    }
  };

  return (
    <View style={styles.container}>
      <Camera
        ref={camera}
        style={StyleSheet.absoluteFill}
        device={device}
        isActive={true}
        photo={true}
      />
      <View style={styles.buttonContainer}>
        <Button title="拍照" onPress={takePhoto} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    position: 'relative',
  },
  buttonContainer: {
    position: 'absolute',
    bottom: 20,
    alignSelf: 'center',
  },
});

拍照参数深度配置

takePhoto方法支持丰富的参数配置,以满足不同场景需求:

参数名类型说明平台支持
flash'on' | 'off' | 'auto'闪光灯模式双平台
enableAutoRedEyeReductionboolean自动红眼消除iOS
enableAutoDistortionCorrectionboolean自动畸变校正iOS
enableShutterSoundboolean是否播放快门声双平台
pathstring自定义保存路径双平台

高级配置示例

// 专业模式拍照配置
const photoOptions = {
  flash: 'auto', // 自动闪光灯
  enableAutoRedEyeReduction: true, // 启用红眼消除
  enableAutoDistortionCorrection: true, // 启用畸变校正
  path: '/storage/emulated/0/DCIM/VisionCamera', // 自定义保存目录
};

// 无声拍照(仅Android)
const silentPhotoOptions = {
  enableShutterSound: false,
};

照片输出格式与元数据

拍照成功后返回PhotoFile对象,包含丰富的图像信息:

interface PhotoFile {
  path: string;          // 文件路径
  width: number;         // 宽度(像素)
  height: number;        // 高度(像素)
  isRawPhoto: boolean;   // 是否为RAW格式
  orientation: Orientation; // 方向信息
  metadata?: {           // 详细元数据
    Orientation: number; // EXIF方向
    '{Exif}': {
      DateTimeOriginal: string; // 拍摄时间
      ExposureTime: number;     // 曝光时间
      FNumber: number;          // 光圈值
      ISOSpeedRatings: number[];// ISO值
      FocalLength: number;      // 焦距
    };
    // 更多元数据...
  };
}

元数据应用示例

// 从照片元数据中提取拍摄信息
const extractPhotoInfo = (photo: PhotoFile) => {
  if (!photo.metadata?.['{Exif}']) return null;
  
  const exif = photo.metadata['{Exif}'];
  return {
    timestamp: exif.DateTimeOriginal,
    exposure: exif.ExposureTime,
    aperture: exif.FNumber,
    iso: exif.ISOSpeedRatings[0],
    focalLength: exif.FocalLength,
  };
};

录像功能完全指南

视频录制基础流程

视频录制通过startRecordingstopRecording等方法实现,需要处理录制状态管理和错误回调:

import React, { useRef, useState } from 'react';
import { View, StyleSheet, Button, Text } from 'react-native';
import { Camera, useCameraDevice, useCameraPermission, useMicrophonePermission } from 'react-native-vision-camera';

export function VideoRecordingExample() {
  const camera = useRef<Camera>(null);
  const [isRecording, setIsRecording] = useState(false);
  const [videoDuration, setVideoDuration] = useState(0);
  const cameraPermission = useCameraPermission();
  const micPermission = useMicrophonePermission();
  const device = useCameraDevice('back');
  
  // 检查权限
  if (cameraPermission.status !== 'granted' || micPermission.status !== 'granted') {
    return <View><Text>请授予相机和麦克风权限</Text></View>;
  }
  
  if (!device) return <View><Text>未找到相机设备</Text></View>;
  
  let recordingTimer;
  
  const startRecording = async () => {
    if (!camera.current) return;
    
    setIsRecording(true);
    setVideoDuration(0);
    
    // 启动计时器
    recordingTimer = setInterval(() => {
      setVideoDuration(prev => prev + 1);
    }, 1000);
    
    try {
      await camera.current.startRecording({
        flash: 'off',
        fileType: 'mp4',
        onRecordingError: (error) => {
          console.error('录制错误:', error);
          setIsRecording(false);
          clearInterval(recordingTimer);
        },
        onRecordingFinished: (video) => {
          console.log('视频保存路径:', video.path);
          console.log('视频时长:', video.duration, '秒');
          setIsRecording(false);
          clearInterval(recordingTimer);
          setVideoDuration(0);
        },
      });
    } catch (e) {
      console.error('启动录制失败:', e);
      setIsRecording(false);
    }
  };
  
  const stopRecording = async () => {
    if (!camera.current || !isRecording) return;
    try {
      await camera.current.stopRecording();
    } catch (e) {
      console.error('停止录制失败:', e);
    }
  };
  
  return (
    <View style={styles.container}>
      <Camera
        ref={camera}
        style={StyleSheet.absoluteFill}
        device={device}
        isActive={true}
        video={true}
        audio={true} // 需要麦克风权限
      />
      <View style={styles.infoBar}>
        <Text style={styles.duration}>{videoDuration}s</Text>
      </View>
      <View style={styles.controls}>
        {isRecording ? (
          <Button title="停止录制" onPress={stopRecording} color="red" />
        ) : (
          <Button title="开始录制" onPress={startRecording} />
        )}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    position: 'relative',
  },
  infoBar: {
    position: 'absolute',
    top: 20,
    left: 20,
    backgroundColor: 'rgba(0,0,0,0.5)',
    padding: 8,
    borderRadius: 4,
  },
  duration: {
    color: 'white',
    fontWeight: 'bold',
  },
  controls: {
    position: 'absolute',
    bottom: 20,
    alignSelf: 'center',
  },
});

高级录制功能实现

视频暂停与恢复

支持暂停录制功能,实现分段录制场景:

// 视频暂停/恢复功能
const [isPaused, setIsPaused] = useState(false);

const togglePauseRecording = async () => {
  if (!camera.current) return;
  
  try {
    if (isPaused) {
      await camera.current.resumeRecording();
      setIsPaused(false);
      // 恢复计时器
    } else {
      await camera.current.pauseRecording();
      setIsPaused(true);
      // 暂停计时器
    }
  } catch (e) {
    console.error('暂停/恢复失败:', e);
  }
};
自定义视频编码与质量

通过配置videoCodec和比特率参数控制视频质量:

// 高质量视频录制配置
const highQualityRecordingOptions = {
  flash: 'off',
  fileType: 'mp4',
  videoCodec: 'h265', // 使用HEVC编码,更高压缩率
  // 比特率控制(两种方式):
  // 1. 直接指定比特率(单位:bps)
  videoBitRate: 10_000_000, // 10Mbps
  // 2. 使用预设等级
  // videoBitRate: 'high', // 'low' | 'normal' | 'high' | 'extra-high'
  onRecordingError: (error) => {/* 错误处理 */},
  onRecordingFinished: (video) => {/* 完成处理 */},
};
视频防抖与HDR配置

通过相机格式选择实现视频防抖和HDR功能:

import { useCameraFormat } from 'react-native-vision-camera';

// 选择支持4K和防抖的相机格式
const format = useCameraFormat(device, [
  { videoResolution: 'ultra-high' }, // 优先4K分辨率
  { videoStabilizationMode: 'cinematic' }, // 优先电影级防抖
  { fps: 60 }, // 优先60fps
]);

// 组件中应用
<Camera
  ref={camera}
  style={StyleSheet.absoluteFill}
  device={device}
  format={format}
  isActive={true}
  video={true}
  audio={true}
  videoStabilizationMode="cinematic"
  videoHdr={true} // 启用视频HDR
/>

视频文件结构与属性

录制完成后返回VideoFile对象:

interface VideoFile {
  path: string;          // 文件路径
  duration: number;      // 时长(秒)
  width: number;         // 宽度(像素)
  height: number;        // 高度(像素)
  size: number;          // 文件大小(字节)
}

视频信息提取示例

// 获取视频文件大小和分辨率信息
const getVideoInfo = async (video: VideoFile) => {
  const fileSizeMB = (video.size / (1024 * 1024)).toFixed(2);
  const resolution = `${video.width}x${video.height}`;
  const duration = new Date(video.duration * 1000).toISOString().substr(11, 8);
  
  return {
    fileSize: `${fileSizeMB} MB`,
    resolution,
    duration,
  };
};

高级功能与性能优化

相机设备管理与切换

实现前后摄像头切换和多设备管理:

const [cameraPosition, setCameraPosition] = useState<'front' | 'back'>('back');
const device = useCameraDevice(cameraPosition);

// 切换摄像头
const toggleCamera = () => {
  setCameraPosition(prev => prev === 'back' ? 'front' : 'back');
};

// UI中添加切换按钮
<Button title="切换摄像头" onPress={toggleCamera} />

多摄像头设备检测

import { Camera } from 'react-native-vision-camera';

// 获取所有可用相机设备
const getAllDevices = () => {
  const devices = Camera.getAvailableCameraDevices();
  return {
    backCameras: devices.filter(d => d.position === 'back'),
    frontCameras: devices.filter(d => d.position === 'front'),
    hasDualCamera: devices.some(d => d.name?.includes('ultra-wide')),
    hasTelephoto: devices.some(d => d.name?.includes('telephoto')),
  };
};

手势控制实现(缩放与对焦)

实现 pinch-to-zoom 和点击对焦功能:

import Animated, { useAnimatedGestureHandler, useSharedValue } from 'react-native-reanimated';

const ReanimatedCamera = Animated.createAnimatedComponent(Camera);

export function CameraWithGestures() {
  const camera = useRef<Camera>(null);
  const zoom = useSharedValue(1);
  const device = useCameraDevice('back');
  
  // 缩放手势处理
  const onPinchGesture = useAnimatedGestureHandler({
    onStart: (_, context) => {
      context.startZoom = zoom.value;
    },
    onActive: (event, context) => {
      const scale = event.scale;
      const startZoom = context.startZoom ?? 1;
      // 计算新的缩放值,限制在设备支持范围内
      const newZoom = Math.min(
        Math.max(startZoom * scale, device?.minZoom ?? 1),
        device?.maxZoom ?? 10
      );
      zoom.value = newZoom;
    },
  });
  
  // 点击对焦处理
  const onFocusTap = (event: GestureResponderEvent) => {
    if (!camera.current || !device?.supportsFocus) return;
    
    // 获取点击位置(相对于相机视图)
    const { locationX, locationY } = event.nativeEvent;
    camera.current.focus({ x: locationX, y: locationY });
    
    // 显示对焦指示器动画
    setFocusPoint({ x: locationX, y: locationY });
    setTimeout(() => setFocusPoint(null), 1000);
  };
  
  // 应用动画属性
  const animatedProps = useAnimatedProps(() => ({
    zoom: zoom.value,
  }));
  
  return (
    <PinchGestureHandler onGestureEvent={onPinchGesture}>
      <Animated.View style={StyleSheet.absoluteFill} onTouchEnd={onFocusTap}>
        <ReanimatedCamera
          ref={camera}
          style={StyleSheet.absoluteFill}
          device={device}
          isActive={true}
          animatedProps={animatedProps}
        />
        {/* 对焦指示器 */}
        {focusPoint && (
          <View style={[styles.focusIndicator, { left: focusPoint.x - 25, top: focusPoint.y - 25 }]} />
        )}
      </Animated.View>
    </PinchGestureHandler>
  );
}

const styles = StyleSheet.create({
  focusIndicator: {
    width: 50,
    height: 50,
    borderWidth: 2,
    borderColor: 'white',
    borderRadius: 50,
    position: 'absolute',
  },
});

错误处理与异常恢复

react-native-vision-camera定义了丰富的错误类型,需要针对性处理:

import { CameraCaptureError, CameraRuntimeError } from 'react-native-vision-camera';

// 错误处理工具函数
const handleCameraError = (error: unknown) => {
  if (error instanceof CameraRuntimeError) {
    switch (error.code) {
      case 'permission/camera-permission-denied':
        return { type: 'permission', message: '相机权限被拒绝,请在设置中启用' };
      case 'device/no-device':
        return { type: 'device', message: '未检测到相机设备' };
      case 'session/camera-not-ready':
        return { type: 'session', message: '相机准备中,请稍后再试' };
      // 更多错误类型...
    }
  } else if (error instanceof CameraCaptureError) {
    switch (error.code) {
      case 'capture/insufficient-storage':
        return { type: 'storage', message: '存储空间不足,无法保存媒体' };
      case 'capture/file-io-error':
        return { type: 'file', message: '文件写入失败' };
      case 'capture/recording-in-progress':
        return { type: 'recording', message: '已有录制进程在进行中' };
      // 更多错误类型...
    }
  }
  return { type: 'unknown', message: '发生未知错误' };
};

// 组件中应用
const takePhotoWithErrorHandling = async () => {
  try {
    const photo = await camera.current.takePhoto({/* 选项 */});
    // 处理成功
  } catch (e) {
    const errorInfo = handleCameraError(e);
    showErrorDialog(errorInfo.message);
    
    // 针对可恢复错误进行处理
    if (errorInfo.type === 'session') {
      // 尝试重启相机
      setIsActive(false);
      setTimeout(() => setIsActive(true), 1000);
    }
  }
};

性能优化最佳实践

相机格式选择策略

使用useCameraFormat钩子选择最优相机格式:

// 不同场景的格式选择策略
const getFormatStrategy = (mode: 'photo' | 'video' | 'slow-mo') => {
  switch (mode) {
    case 'photo':
      return [
        { photoResolution: 'max' }, // 最高照片分辨率
        { photoAspectRatio: 1 }, // 优先1:1比例(正方形)
        { supportsPhotoHdr: true }, // 启用HDR
      ];
    case 'video':
      return [
        { videoResolution: 'high' }, // 1080p分辨率
        { fps: 60 }, // 60fps
        { videoStabilizationMode: 'standard' }, // 标准防抖
      ];
    case 'slow-mo':
      return [
        { fps: 120 }, // 120fps以上支持慢动作
        { videoResolution: 'medium' }, // 降低分辨率以支持高帧率
      ];
  }
};

// 使用策略选择格式
const format = useCameraFormat(device, getFormatStrategy(currentMode));
帧率控制与电池优化

合理设置帧率平衡性能与功耗:

// 根据场景动态调整帧率
const getFpsRange = (isLowPowerMode: boolean, isRecording: boolean) => {
  if (isLowPowerMode) {
    return [15, 30]; // 低电量模式下降低帧率
  } else if (isRecording) {
    return 60; // 录制时使用高帧率
  } else {
    return [30, 60]; // 预览时动态帧率
  }
};

// 应用到相机组件
<Camera
  {/* ...其他属性 */}
  fps={getFpsRange(isLowPowerMode, isRecording)}
  enableBufferCompression={!isRecording} // 非录制时启用缓冲区压缩
/>

实战案例:功能完整的相机应用

综合示例:相机应用核心组件

以下是整合拍照、录像、切换摄像头、手势控制等功能的完整相机组件:

import React, { useRef, useState, useEffect } from 'react';
import { View, StyleSheet, TouchableOpacity, Text, Image } from 'react-native';
import {
  Camera,
  useCameraDevice,
  useCameraPermission,
  useMicrophonePermission,
  useCameraFormat,
} from 'react-native-vision-camera';
import { PinchGestureHandler } from 'react-native-gesture-handler';
import Animated, { useAnimatedGestureHandler, useSharedValue, useAnimatedProps } from 'react-native-reanimated';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';

// 定义相机模式
type CameraMode = 'photo' | 'video';

const ReanimatedCamera = Animated.createAnimatedComponent(Camera);

export function AdvancedCamera() {
  // 状态管理
  const [mode, setMode] = useState<CameraMode>('photo');
  const [isRecording, setIsRecording] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const [recordingTime, setRecordingTime] = useState(0);
  const [cameraPosition, setCameraPosition] = useState<'front' | 'back'>('back');
  const [flashMode, setFlashMode] = useState<'off' | 'on' | 'auto'>('auto');
  const [focusPoint, setFocusPoint] = useState<{ x: number; y: number } | null>(null);
  
  // 引用与动画值
  const camera = useRef<Camera>(null);
  const zoom = useSharedValue(1);
  const recordingTimer = useRef<NodeJS.Timeout | null>(null);
  
  // 权限检查
  const cameraPermission = useCameraPermission();
  const micPermission = useMicrophonePermission();
  
  // 设备与格式
  const device = useCameraDevice(cameraPosition);
  const format = useCameraFormat(device, [
    { videoAspectRatio: 16 / 9 },
    mode === 'photo' ? { photoResolution: 'max' } : { videoResolution: 'high' },
    { fps: mode === 'video' ? 60 : 30 },
  ]);
  
  // 处理权限状态
  if (cameraPermission.status !== 'granted' || (mode === 'video' && micPermission.status !== 'granted')) {
    return (
      <View style={styles.permissionContainer}>
        <Text style={styles.permissionText}>
          {cameraPermission.status !== 'granted' 
            ? '需要相机权限' 
            : '需要麦克风权限'}
        </Text>
      </View>
    );
  }
  
  if (!device || !format) {
    return (
      <View style={styles.errorContainer}>
        <Text style={styles.errorText}>未找到相机设备</Text>
      </View>
    );
  }
  
  // 缩放手势处理
  const onPinchGesture = useAnimatedGestureHandler({
    onStart: (_, context) => {
      context.startZoom = zoom.value;
    },
    onActive: (event, context) => {
      const startZoom = context.startZoom ?? 1;
      const newZoom = startZoom * event.scale;
      zoom.value = Math.min(Math.max(newZoom, device.minZoom), device.maxZoom);
    },
  });
  
  // 对焦处理
  const handleFocus = (event: React.TouchEvent) => {
    if (!camera.current || !device.supportsFocus) return;
    
    const { locationX, locationY } = event.nativeEvent;
    camera.current.focus({ x: locationX, y: locationY });
    setFocusPoint({ x: locationX, y: locationY });
    setTimeout(() => setFocusPoint(null), 1500);
  };
  
  // 切换相机
  const toggleCamera = () => {
    setCameraPosition(prev => (prev === 'back' ? 'front' : 'back'));
    setZoomValue(1); // 重置缩放
  };
  
  // 切换闪光灯
  const toggleFlash = () => {
    const modes: Array<'off' | 'on' | 'auto'> = ['off', 'on', 'auto'];
    const currentIndex = modes.indexOf(flashMode);
    setFlashMode(modes[(currentIndex + 1) % modes.length]);
  };
  
  // 切换拍摄模式
  const toggleMode = () => {
    setMode(prev => (prev === 'photo' ? 'video' : 'photo'));
    setFlashMode('auto'); // 重置闪光灯
  };
  
  // 开始录制
  const startRecording = async () => {
    if (!camera.current || isRecording) return;
    
    setIsRecording(true);
    setIsPaused(false);
    setRecordingTime(0);
    
    // 启动计时器
    recordingTimer.current = setInterval(() => {
      setRecordingTime(prev => prev + 1);
    }, 1000);
    
    try {
      await camera.current.startRecording({
        flash: flashMode === 'auto' ? 'off' : flashMode,
        fileType: 'mp4',
        videoBitRate: 'high',
        onRecordingError: (error) => {
          console.error('录制错误:', error);
          stopRecording();
        },
        onRecordingFinished: (video) => {
          console.log('视频保存成功:', video.path);
          // 导航到预览页面
          // navigation.navigate('Preview', { path: video.path, type: 'video' });
        },
      });
    } catch (e) {
      console.error('启动录制失败:', e);
      stopRecording();
    }
  };
  
  // 停止录制
  const stopRecording = async () => {
    if (!camera.current || !isRecording || isPaused) return;
    
    try {
      await camera.current.stopRecording();
    } catch (e) {
      console.error('停止录制失败:', e);
    } finally {
      setIsRecording(false);
      if (recordingTimer.current) {
        clearInterval(recordingTimer.current);
        recordingTimer.current = null;
      }
    }
  };
  
  // 暂停/恢复录制
  const togglePauseRecording = async () => {
    if (!camera.current || !isRecording) return;
    
    try {
      if (isPaused) {
        await camera.current.resumeRecording();
        // 恢复计时器
        recordingTimer.current = setInterval(() => {
          setRecordingTime(prev => prev + 1);
        }, 1000);
      } else {
        await camera.current.pauseRecording();
        // 暂停计时器
        if (recordingTimer.current) {
          clearInterval(recordingTimer.current);
          recordingTimer.current = null;
        }
      }
      setIsPaused(prev => !prev);
    } catch (e) {
      console.error('暂停/恢复失败:', e);
    }
  };
  
  // 拍照
  const takePhoto = async () => {
    if (!camera.current || isRecording) return;
    
    try {
      const photo = await camera.current.takePhoto({
        flash: flashMode,
        enableAutoRedEyeReduction: true,
      });
      console.log('照片保存成功:', photo.path);
      // 导航到预览页面
      // navigation.navigate('Preview', { path: photo.path, type: 'photo' });
    } catch (e) {
      console.error('拍照失败:', e);
    }
  };
  
  // 格式化录制时间
  const formatTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  };
  
  // 动画属性
  const animatedProps = useAnimatedProps(() => ({
    zoom: zoom.value,
  }));
  
  const setZoomValue = (value: number) => {
    zoom.value = Math.min(Math.max(value, device.minZoom), device.maxZoom);
  };
  
  return (
    <View style={styles.container}>
      <PinchGestureHandler onGestureEvent={onPinchGesture}>
        <View style={StyleSheet.absoluteFill} onTouchEnd={handleFocus}>
          <ReanimatedCamera
            ref={camera}
            style={StyleSheet.absoluteFill}
            device={device}
            format={format}
            isActive={true}
            photo={mode === 'photo'}
            video={mode === 'video'}
            audio={mode === 'video'}
            flash={flashMode}
            fps={mode === 'video' ? 60 : 30}
            animatedProps={animatedProps}
            enableFpsGraph={__DEV__} // 开发模式显示FPS图表
          />
          
          {/* 对焦指示器 */}
          {focusPoint && (
            <View style={[styles.focusIndicator, { left: focusPoint.x - 25, top: focusPoint.y - 25 }]} />
          )}
          
          {/* 顶部控制栏 */}
          <View style={styles.topBar}>
            <TouchableOpacity style={styles.controlButton} onPress={toggleFlash}>
              <MaterialIcons
                name={
                  flashMode === 'on' ? 'flash-on' :
                  flashMode === 'off' ? 'flash-off' : 'flash-auto'
                }
                color="white"
                size={24}
              />
            </TouchableOpacity>
            
            <TouchableOpacity style={styles.controlButton} onPress={toggleCamera}>
              <MaterialIcons name="flip-camera-ios" color="white" size={24} />
            </TouchableOpacity>
          </View>
          
          {/* 底部控制栏 */}
          <View style={styles.bottomBar}>
            <TouchableOpacity style={styles.modeButton} onPress={toggleMode}>
              <Text style={[styles.modeText, { fontWeight: mode === 'photo' ? 'bold' : 'normal' }]}>
                照片
              </Text>
              <Text style={[styles.modeText, { fontWeight: mode === 'video' ? 'bold' : 'normal' }]}>
                视频
              </Text>
            </TouchableOpacity>
            
            {/* 拍摄按钮 */}
            <TouchableOpacity
              style={[styles.captureButton, isRecording && styles.recordingButton]}
              onPress={mode === 'photo' ? takePhoto : isRecording ? stopRecording : startRecording}
              onLongPress={mode === 'video' && !isRecording ? startRecording : undefined}
              activeOpacity={0.8}
            >
              {isRecording && isPaused && (
                <View style={styles.pauseIndicator} />
              )}
            </TouchableOpacity>
            
            {/* 预览按钮 */}
            <View style={styles.previewButton}>
              {/* 这里应该显示最后拍摄的照片缩略图 */}

【免费下载链接】react-native-vision-camera 📸 A powerful, high-performance React Native Camera library. 【免费下载链接】react-native-vision-camera 项目地址: https://gitcode.com/GitHub_Trending/re/react-native-vision-camera

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值