커스터마이징
CameraView 위에 자체 RN UI를 올려 가이드·버튼·결과 화면을 구성하는 방법.
이 가이드를 시작하기 전에 기본 사용법을 완료하세요.
개요
<CameraView>는 카메라 프리뷰와 SDK 탐지 오버레이(코/얼굴 마커·진행 링)를 네이티브로 렌더합니다. 그 위에 가이드 메시지, 버튼, 진행률, 결과 화면 같은 앱 UI는 일반 RN 뷰를 absolute로 겹쳐서 직접 구성합니다. UI는 onDetectionStatus / onDetectionProgress / onDetectionFinished 이벤트와 camera 커맨드로 구동합니다.
탐지 마커(코/얼굴)는 SDK가 직접 그립니다. 추가로 검출 rect(코/얼굴 normalized box)가 onDetectionResult로 JS에 노출되므로, 마커 위치를 따라다니는 커스텀 가이드도 RN에서 직접 만들 수 있습니다(아래 예시).
기본 패턴
<CameraView>를 화면에 깔고, 그 위에 오버레이 컨테이너를 겹칩니다. 터치가 카메라 영역으로도 지나가도록 pointerEvents="box-none"을 씁니다.
import { View, StyleSheet } from 'react-native';
<View style={{ flex: 1 }}>
<CameraView
camera={camera}
species="DOG"
purpose="PET_PROFILE_REGISTRATION"
captureSessionId={captureSessionId}
style={StyleSheet.absoluteFill}
onDetectionStatus={setStatus}
onDetectionProgress={setProgress}
onDetectionFinished={onFinished}
/>
{/* 앱 UI 오버레이 */}
<SafeAreaView style={StyleSheet.absoluteFill} pointerEvents="box-none">
{/* ...가이드 / 버튼 / 진행률... */}
</SafeAreaView>
</View>예제: 상단 버튼 (전환 / 닫기)
<View style={styles.topRow} pointerEvents="box-none">
<Pressable onPress={() => camera.switchCamera()}>
<Text style={styles.btn}>전환</Text>
</Pressable>
<Pressable onPress={onClose}>
<Text style={styles.btn}>닫기</Text>
</Pressable>
</View>예제: 상태별 가이드 메시지
onDetectionStatus를 상태로 받아 사용자 안내 문구를 그립니다.
const [status, setStatus] = useState<DetectionStatus | null>(null);
function guideMessage(s: DetectionStatus | null): string {
if (!s) return '카메라 준비 중...';
switch (s.type) {
case 'noObject': return '반려동물을 화면 중앙에 맞춰주세요';
case 'processing': return '인식 중...';
case 'detected': return '좋아요! 그대로 유지하세요';
case 'finished': return '촬영 완료!';
case 'failed': return `다시 시도: ${s.reason}`;
}
}
<Text style={styles.guideCapsule}>{guideMessage(status)}</Text>예제: 진행률
const [progress, setProgress] = useState(0); // onDetectionProgress (0~100)
<View style={styles.progressTrack}>
<View style={[styles.progressFill, { width: `${progress}%` }]} />
</View>예제: 결과 화면과 재촬영
onDetectionFinished로 완료를 받으면 결과/업로드 UI를 띄우고, "다시 찍기"에서 camera.startDetection()으로 재시작합니다.
const [result, setResult] = useState<CameraResult | null>(null);
const onFinished = useCallback((r: CameraResult) => {
setResult(r);
upload(r); // file:// URI들을 앱 서버로 업로드
}, []);
const retake = useCallback(() => {
setResult(null);
setStatus(null);
setProgress(0);
camera.startDetection();
}, [camera]);
{result && (
<View style={styles.resultSheet}>
<Text>촬영 완료 — 지문 {result.fingerprintImages.length}장</Text>
<Pressable onPress={retake}><Text>다시 찍기</Text></Pressable>
</View>
)}예제: 검출 rect 추적 오버레이
onDetectionResult로 코/얼굴 박스(normalized 0–1, 좌상단 원점)를 받아, 그 위치를 따라다니는 커스텀 마커를 직접 그릴 수 있습니다. 뷰 크기는 onLayout으로 얻어 normalized 좌표를 픽셀로 변환합니다.
import { useState } from 'react';
import { View, StyleSheet } from 'react-native';
import type { DetectionResult } from '@petify/react-native-camera-ui';
const [rect, setRect] = useState<DetectionResult['nose']>(null);
const [size, setSize] = useState({ w: 0, h: 0 });
<View
style={{ flex: 1 }}
onLayout={(e) =>
setSize({ w: e.nativeEvent.layout.width, h: e.nativeEvent.layout.height })
}
>
<CameraView
camera={camera}
species="DOG"
purpose="PET_PROFILE_REGISTRATION"
captureSessionId={captureSessionId}
style={StyleSheet.absoluteFill}
onDetectionResult={(r: DetectionResult) => setRect(r.nose ?? r.face)}
/>
{rect && (
<View
pointerEvents="none"
style={{
position: 'absolute',
left: rect.x * size.w,
top: rect.y * size.h,
width: rect.width * size.w,
height: rect.height * size.h,
borderWidth: 2,
borderColor: '#FF592C',
borderRadius: 8,
}}
/>
)}
</View>nose/face는 각각{ x, y, width, height }(normalized 0–1) 또는null입니다. 미검출 프레임에서는null이 될 수 있으니 가드하세요.- SDK 내장 마커와 별개로 그려지므로, 내장 마커가 충분하면 이 오버레이는 생략해도 됩니다.
팁
- 오버레이 컨테이너와 탭이 필요 없는 영역에는
pointerEvents="box-none"을, 버튼 같은 인터랙션 요소에만 기본 동작을 두세요. - 일시정지가 필요하면(예: 시트/팝업 표시)
camera.pauseDetection()후camera.resumeDetection()으로 진행률을 보존하며 재개할 수 있습니다. - 가이드 문구·실패 사유 매핑은 앱 톤에 맞게 자유롭게 바꾸세요.
다음 단계
- 기본 사용법 — hook·이벤트·커맨드 레퍼런스