Camera2预览在TextureView中缩放与方向异常问题求助
相机TextureView预览缩放与方向问题解决方案
一、缩放比例异常问题
问题根源
你当前的onMeasure逻辑直接使用相机预览的原始宽高比(通常是横屏比例,如16:9)适配TextureView的布局空间,但没有考虑屏幕横竖屏状态下的比例反转。比如竖屏时,TextureView的可用空间是高>宽,此时用相机的横屏比例计算会导致宽高适配逻辑颠倒,最终出现水平轴拉伸过度的情况。另外,如果相机预览尺寸的比例与TextureView最终显示的比例不匹配(比如选了4:3的预览尺寸却要适配16:9的View),也会导致强制拉伸。
解决方案
- 动态适配横竖屏比例
修改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); } }
- 匹配相机预览尺寸与View比例
选择相机支持的、与TextureView最终显示比例最接近的预览尺寸,比如如果View是16:9,优先选相机的16:9尺寸(如1920x1080),避免跨比例适配导致的拉伸。
二、方向异常问题
问题根源
你设置的CaptureRequest.JPEG_ORIENTATION仅影响拍摄生成的JPEG照片方向,完全不作用于预览画面。预览画面的方向需要根据屏幕旋转角度和相机传感器方向,调整TextureView的旋转角度来修正;同时前置相机还需要处理镜像翻转,否则反向竖屏时会出现画面颠倒。
解决方案
- 计算正确的预览旋转角度
根据屏幕旋转角度和相机传感器方向,计算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; } }
- 设置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);
- 监听屏幕旋转事件
在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
相关产品推荐
相关产品推荐

