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

Camera2预览在TextureView中缩放与方向异常问题求助

相机TextureView预览缩放与方向问题解决方案

一、缩放比例异常问题

问题根源

你当前的onMeasure逻辑直接使用相机预览的原始宽高比(通常是横屏比例,如16:9)适配TextureView的布局空间,但没有考虑屏幕横竖屏状态下的比例反转。比如竖屏时,TextureView的可用空间是高>宽,此时用相机的横屏比例计算会导致宽高适配逻辑颠倒,最终出现水平轴拉伸过度的情况。另外,如果相机预览尺寸的比例与TextureView最终显示的比例不匹配(比如选了4:3的预览尺寸却要适配16:9的View),也会导致强制拉伸。

解决方案

  1. 动态适配横竖屏比例
    修改onMeasure逻辑,基于相机预览的实际比例和当前View的布局比例进行计算,避免比例颠倒:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
        return;
    }

    // 相机预览的实际比例(如16:9)
    float previewRatio = (float) mRatioWidth / mRatioHeight;
    // 当前View的布局比例
    float viewRatio = (float) width / height;

    if (previewRatio > viewRatio) {
        // 相机比例更宽,以View宽度为基准计算高度
        setMeasuredDimension(width, (int) (width / previewRatio));
    } else {
        // 相机比例更高,以View高度为基准计算宽度
        setMeasuredDimension((int) (height * previewRatio), height);
    }
}
  1. 匹配相机预览尺寸与View比例
    选择相机支持的、与TextureView最终显示比例最接近的预览尺寸,比如如果View是16:9,优先选相机的16:9尺寸(如1920x1080),避免跨比例适配导致的拉伸。

二、方向异常问题

问题根源

你设置的CaptureRequest.JPEG_ORIENTATION仅影响拍摄生成的JPEG照片方向,完全不作用于预览画面。预览画面的方向需要根据屏幕旋转角度和相机传感器方向,调整TextureView的旋转角度来修正;同时前置相机还需要处理镜像翻转,否则反向竖屏时会出现画面颠倒。

解决方案

  1. 计算正确的预览旋转角度
    根据屏幕旋转角度和相机传感器方向,计算TextureView需要旋转的角度:
private int getPreviewRotation(String cameraId, Context context) {
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    int screenRotation = windowManager.getDefaultDisplay().getRotation();
    int screenDegrees = 0;
    switch (screenRotation) {
        case Surface.ROTATION_0: screenDegrees = 0; break;
        case Surface.ROTATION_90: screenDegrees = 90; break;
        case Surface.ROTATION_180: screenDegrees = 180; break;
        case Surface.ROTATION_270: screenDegrees = 270; break;
    }

    // 获取相机传感器的自然方向
    CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    try {
        CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
        int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        
        // 计算最终旋转角度,适配屏幕与传感器方向
        int rotation = (sensorOrientation - screenDegrees + 360) % 360;
        
        // 前置相机需要镜像处理
        boolean isFront = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT;
        if (isFront) {
            rotation = (360 - rotation) % 360;
        }
        return rotation;
    } catch (CameraAccessException e) {
        e.printStackTrace();
        return 0;
    }
}
  1. 设置TextureView旋转与镜像
    在相机初始化完成后,或者屏幕旋转时,更新TextureView的状态:
// 计算旋转角度
int previewRotation = getPreviewRotation(mCameraId, getContext());
// 设置旋转
textureView.setRotation(previewRotation);

// 前置相机设置镜像
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(mCameraId);
boolean isFront = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT;
textureView.setScaleX(isFront ? -1 : 1);
  1. 监听屏幕旋转事件
    在Activity或Fragment中重写onConfigurationChanged方法,当屏幕旋转时重新计算旋转角度并更新TextureView,避免方向异常:
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    // 重新计算并设置预览旋转
    int previewRotation = getPreviewRotation(mCameraId, getContext());
    textureView.setRotation(previewRotation);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:07:53