๐Ÿ“šย Reference


๐Ÿ“œย Chapter


react-native-vision-camera


ํ™”๋ฉด ๋น„์œจ


์˜ˆ์‹œ


// VisionCamera pause/resume + UI overlay ์˜ˆ์ œ

import React, { useEffect, useRef, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, PermissionsAndroid, Platform } from 'react-native';
import { Camera, useCameraDevices } from 'react-native-vision-camera';

export default function RecordingScreen() {
  const camera = useRef(null);
  const [hasPermission, setHasPermission] = useState(false);
  const [isRecording, setIsRecording] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const devices = useCameraDevices();
  const device = devices.back;

  useEffect(() => {
    (async () => {
      const status = await Camera.requestCameraPermission();
      if (Platform.OS === 'android') {
        await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO);
      }
      setHasPermission(status === 'authorized');
    })();
  }, []);

  const startRecording = async () => {
    if (camera.current) {
      setIsRecording(true);
      setIsPaused(false);
      await camera.current.startRecording({
        flash: 'off',
        onRecordingFinished: (video) => {
          console.log('Recording finished:', video);
          setIsRecording(false);
        },
        onRecordingError: (error) => {
          console.error('Recording error:', error);
        },
      });
    }
  };

  const pauseRecording = async () => {
    if (camera.current && isRecording && !isPaused) {
      await camera.current.pauseRecording();
      setIsPaused(true);
    }
  };

  const resumeRecording = async () => {
    if (camera.current && isRecording && isPaused) {
      await camera.current.resumeRecording();
      setIsPaused(false);
    }
  };

  const stopRecording = async () => {
    if (camera.current && isRecording) {
      await camera.current.stopRecording();
      setIsRecording(false);
      setIsPaused(false);
    }
  };

  if (!device || !hasPermission) {
    return <Text>์นด๋ฉ”๋ผ ๊ถŒํ•œ ์—†์Œ ๋˜๋Š” ์žฅ์น˜ ์—†์Œ</Text>;
  }

  return (
    <View style={styles.container}>
      <Camera
        ref={camera}
        style={StyleSheet.absoluteFill}
        device={device}
        isActive={true}
        video={true}
        audio={true}
      />

      {/* ์˜ค๋ฒ„๋ ˆ์ด UI */}
      <View style={styles.overlay}>
        {!isRecording ? (
          <TouchableOpacity style={styles.button} onPress={startRecording}>
            <Text style={styles.buttonText}>Start</Text>
          </TouchableOpacity>
        ) : (
          <View style={styles.row}>
            <TouchableOpacity style={styles.button} onPress={pauseRecording}>
              <Text style={styles.buttonText}>Pause</Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.button} onPress={resumeRecording}>
              <Text style={styles.buttonText}>Resume</Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.button} onPress={stopRecording}>
              <Text style={styles.buttonText}>Stop</Text>
            </TouchableOpacity>
          </View>
        )}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'black',
  },
  overlay: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'flex-end',
    alignItems: 'center',
    paddingBottom: 40,
    backgroundColor: 'transparent',
  },
  row: {
    flexDirection: 'row',
    gap: 12,
  },
  button: {
    backgroundColor: '#ff5555',
    paddingHorizontal: 24,
    paddingVertical: 12,
    borderRadius: 24,
    marginHorizontal: 8,
  },
  buttonText: {
    color: 'white',
    fontWeight: 'bold',
  },
});