React Native Vision Camera初始化闪白屏,如何设置feed就绪前的加载状态?
问题:react-native-vision-camera初始化前白屏闪烁,加载状态未生效
初始化react-native-vision-camera的<Camera>组件时,组件显示前会出现白屏闪烁。已实现相机权限校验,但加载状态(加载GIF)未触发,测试确认加载状态未优先执行,需求是在相机feed加载完成前显示加载状态。
原实现代码:
import React, {useEffect, useState, useRef} from 'react'; import GlobalStyles from '../constants/styles.js'; import { Camera, useCameraDevice, useCameraDevices, } from 'react-native-vision-camera'; import {Text, View, Image, Alert, Linking} from 'react-native'; export default () => { const [loading, setLoading] = useState(true); const [cameraPermission, setCameraPermission] = useState(false); const [cameraOrientation, setCameraOrientation] = useState('front'); const camera = useRef(null); const device = useCameraDevice(cameraOrientation); // 检查设备相机权限 const checkCameraPermission = async () => { console.info('Performing Permissions Check ...'); const status = await Camera.getCameraPermissionStatus(); switch (status) { case 'granted': setCameraPermission(true); setLoading(false); console.info('Permissions Checked'); break; case 'not-determined': const newStatus = await Camera.requestCameraPermission(); setCameraPermission(status === 'granted'); if (status != 'granted') { Alert.alert( 'Camera Permission Denied', 'Camera access has not been granted to the application, please provide access to the camera', [ { text: 'Open Permissions', onPress: () => Linking.openSettings(), }, ], ); } else { console.info('Permissions Checked'); } setLoading(false); break; case 'denied': Alert.alert( 'Camera Permission Denied', 'Camera access has not been granted to the application, please provide access to the camera', [ { text: 'Open Permissions', onPress: () => Linking.openSettings(), }, ], ); break; case 'restricted': Alert.alert( 'Camera Permission Denied', 'Camera access has not been granted to the application, please provide access to the camera', [ { text: 'Open Permissions', onPress: () => Linking.openSettings(), }, ], ); break; } }; useEffect(() => { checkCameraPermission(); }, []); return ( <View style={{flex: 1}}> {loading || !cameraPermission ? ( <View style={{flex: 1}}> {/* Camera rendered to prevent error */} <Camera ref={camera} style={{opacity: 0}} device={device} isActive={true} photo={true} /> <View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center', }}> <Image source={require('../resources/gif/loading.gif')} style={{ width: 35, height: 35, }} /> </View> </View> ) : ( <View style={{flex: 1}}> <Camera ref={camera} style={{flex: 1}} device={device} isActive={true} photo={true} /> </View> )} </View> ); };
测试时曾在<Camera>组件下方添加以下代码(移除了(loading || !cameraPermission)状态中的GIF):
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center', }}> <Image source={require('../resources/gif/loading.gif')} style={{ width: 35, height: 35, }} /> </View>
解决方案
问题根源
- 原代码在权限校验完成后直接设置
loading=false,但此时相机feed尚未完成加载,导致白屏 - 权限请求逻辑存在错误:
setCameraPermission(status === 'granted')中使用了旧的status变量,应该用请求后的newStatus - 未监听相机组件的初始化完成事件,无法准确判断feed是否加载完毕
修改方案
- 新增
isCameraReady状态,用于监听相机是否初始化完成 - 给
<Camera>组件添加onInitialized回调,相机准备好时将isCameraReady设为true - 调整加载状态的判断条件:
loading || !cameraPermission || !isCameraReady,确保三个条件都满足才隐藏加载动画 - 修正权限请求中的变量错误
修改后的完整代码
import React, {useEffect, useState, useRef} from 'react'; import GlobalStyles from '../constants/styles.js'; import { Camera, useCameraDevice, useCameraDevices, } from 'react-native-vision-camera'; import {Text, View, Image, Alert, Linking} from 'react-native'; export default () => { const [loading, setLoading] = useState(true); const [cameraPermission, setCameraPermission] = useState(false); const [cameraOrientation, setCameraOrientation] = useState('front'); // 新增状态:标记相机是否初始化完成 const [isCameraReady, setIsCameraReady] = useState(false); const camera = useRef(null); const device = useCameraDevice(cameraOrientation); // 检查设备相机权限 const checkCameraPermission = async () => { console.info('Performing Permissions Check ...'); const status = await Camera.getCameraPermissionStatus(); switch (status) { case 'granted': setCameraPermission(true); // 权限通过后不立即关闭loading,等待相机初始化完成 console.info('Permissions Checked'); break; case 'not-determined': const newStatus = await Camera.requestCameraPermission(); // 修正:使用newStatus判断权限是否通过 setCameraPermission(newStatus === 'granted'); if (newStatus !== 'granted') { Alert.alert( 'Camera Permission Denied', 'Camera access has not been granted to the application, please provide access to the camera', [ { text: 'Open Permissions', onPress: () => Linking.openSettings(), }, ], ); setLoading(false); } else { console.info('Permissions Checked'); } break; case 'denied': case 'restricted': Alert.alert( 'Camera Permission Denied', 'Camera access has not been granted to the application, please provide access to the camera', [ { text: 'Open Permissions', onPress: () => Linking.openSettings(), }, ], ); setLoading(false); break; } }; useEffect(() => { checkCameraPermission(); }, []); return ( <View style={{flex: 1}}> {/* 调整判断条件:权限未通过/加载中/相机未准备好时显示加载动画 */} {loading || !cameraPermission || !isCameraReady ? ( <View style={{flex: 1}}> {/* 保持透明相机组件避免错误 */} <Camera ref={camera} style={{opacity: 0}} device={device} isActive={cameraPermission} photo={true} // 添加相机初始化完成回调 onInitialized={() => { setIsCameraReady(true); setLoading(false); }} /> <View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center', backgroundColor: '#000', // 添加黑色背景避免白屏闪烁 }}> <Image source={require('../resources/gif/loading.gif')} style={{ width: 35, height: 35, }} /> </View> </View> ) : ( <View style={{flex: 1}}> <Camera ref={camera} style={{flex: 1}} device={device} isActive={true} photo={true} /> </View> )} </View> ); };
额外优化点
- 给加载动画的容器添加
backgroundColor: '#000',避免权限通过后到相机加载完成前的白屏 - 权限被拒绝时立即关闭loading,避免不必要的加载状态停留
内容的提问来源于stack exchange,提问作者Oscar Bale
相关产品推荐
相关产品推荐

