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

React Native Vision Camera v2.16.2 Android相机界面显示异常求助

React Native Vision Camera v2.16.2 画面偏移及布局异常解决方案

问题现象

使用React Native集成Vision Camera v2.16.2版本(因新版本与当前RN版本不兼容),相机权限请求成功后打开,但界面显示异常:画面偏移出屏幕,圆形拍照按钮跑到屏幕顶部,调整布局后问题仍未解决。

解决方案

1. 调整容器基础布局

移除父容器的justifyContent: 'center'和alignItems: 'center',避免干扰绝对定位元素的布局逻辑,保持容器为全屏flex容器即可。

2. 修正Camera组件适配

为Camera组件添加format属性,选择与屏幕比例匹配的相机格式,避免画面拉伸或偏移。

3. 修复图片路径语法错误

原代码中图片URI的file://'${imageSource}'多了单引号,会导致图片加载失败,需修正为正确的格式。

修改后的完整代码

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

function AddPicture() {
  const [cameraPosition, setCameraPosition] = useState('back')
  const [showCamera, setShowCamera] = useState(true);
  const [imageSource, setImageSource] = useState('');

  const devices = useCameraDevices()?.[cameraPosition];
  const camera = useRef(null);

  useEffect(() => {
    async function getPermission() {
      const newCameraPermission = await Camera.requestCameraPermission();
      console.log("permission status: ", newCameraPermission);
      if (newCameraPermission === 'denied') {
        await Linking.openSettings();
      }
    };
    getPermission();
  }, []);

  const capturePhoto = async () => {
    if (camera.current !== null) {
      const photo = await camera.current.takePhoto({
        flash:'on'
      });
      setImageSource(photo.path);
      setShowCamera(false);
      console.log(photo.path);
    }
  };

  const handleBack = () => {
    setShowCamera(true);
    setImageSource('');
  };

  if (devices == null) {
    return <Text>Camera not available</Text>;
  }

  // 选择适配屏幕的相机格式
  const format = devices.formats.find(f => f.videoWidth / f.videoHeight === 9/16) || devices.formats[0];

  return (
    <View style={styles.container}>
      
      {showCamera ? (
        <>
          <Camera
            ref={camera}
            style={StyleSheet.absoluteFill}
            device={devices}
            isActive={showCamera}
            photo={true}
            format={format} // 添加格式适配
          />

          <View style={styles.buttonContainer}>
            <TouchableOpacity
              style={styles.camButton}
              onPress={() => capturePhoto()}
            />
          </View>
        </>
      ) : (
        <>
          {imageSource !== '' ? (
            <Image
              style={styles.image}
              source={{
                uri: `file://${imageSource}`, // 修正路径语法
              }}
            />
          ) : null}

          <View style={styles.backButton}>
            <TouchableOpacity
              style={{
                backgroundColor: 'rgba(0,0,0,0.2)',
                padding: 10,
                justifyContent: 'center',
                alignItems: 'center',
                borderRadius: 10,
                borderWidth: 2,
                borderColor: '#fff',
                width: 100,
              }}
              onPress={handleBack}>
              <Text style={{color: 'white', fontWeight: '500'}}>Back</Text>
            </TouchableOpacity>
          </View>
          <View style={styles.buttonContainer}>
            <View style={styles.buttons}>
              <TouchableOpacity
                style={{
                  backgroundColor: '#fff',
                  padding: 10,
                  justifyContent: 'center',
                  alignItems: 'center',
                  borderRadius: 10,
                  borderWidth: 2,
                  borderColor: '#77c3ec',
                }}
                onPress={() => setShowCamera(true)}>
                <Text style={{color: '#77c3ec', fontWeight: '500'}}>
                  Retake
                </Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={{
                  backgroundColor: '#77c3ec',
                  padding: 10,
                  justifyContent: 'center',
                  alignItems: 'center',
                  borderRadius: 10,
                  borderWidth: 2,
                  borderColor: 'white',
                }}
                onPress={() => {
                  setShowCamera(true)
                  setImageSource('');
                }}>
                <Text style={{color: 'white', fontWeight: '500'}}>
                  Use Photo
                </Text>
              </TouchableOpacity>
            </View>
          </View>
        </>
      )}
    </View>
  );
}

export default AddPicture;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    // 移除居中属性,避免干扰绝对定位元素
  },
  button: {
    backgroundColor: 'gray',
  },
  backButton: {
    backgroundColor: 'rgba(0,0,0,0.0)',
    position: 'absolute',
    justifyContent: 'center',
    width: '100%',
    top: 0,
    padding: 20,
  },
  buttonContainer: {
    backgroundColor: 'rgba(0,0,0,0.2)',
    position: 'absolute',
    justifyContent: 'center',
    alignItems: 'center',
    width: '100%',
    bottom: 0,
    padding: 20,
  },
  buttons: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    width: '100%',
  },
  camButton: {
    height: 80,
    width: 80,
    borderRadius: 40,
    backgroundColor: '#B2BEB5',
    alignSelf: 'center',
    borderWidth: 4,
    borderColor: 'white',
  },
  image: {
    width: '100%',
    height: '100%',
    aspectRatio: 9 / 16,
  },
});

额外说明

  • 若仍存在画面适配问题,可尝试调整format的选择逻辑,比如优先选择支持最高分辨率的格式,或者根据设备屏幕尺寸动态计算比例。
  • 确保项目中已正确配置Vision Camera的原生依赖,比如iOS的Info.plist权限声明、Android的AndroidManifest.xml权限配置。

内容的提问来源于stack exchange,提问作者jordyng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:49:52