You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
解决方案

问题根源

  1. 原代码在权限校验完成后直接设置loading=false,但此时相机feed尚未完成加载,导致白屏
  2. 权限请求逻辑存在错误:setCameraPermission(status === 'granted')中使用了旧的status变量,应该用请求后的newStatus
  3. 未监听相机组件的初始化完成事件,无法准确判断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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:05:55