关于CameraX预览视图宽高比在高分辨率设备上不生效的问询
解决CameraX高分辨率设备预览比例失效问题
问题根源
你的代码里有几个关键问题,导致Pixel 8 Pro、vivo V30 Pro这类高分辨率设备上比例设置没生效:
- UseCaseGroup白创建了:你明明搭好了带Viewport的UseCaseGroup,但最后绑定生命周期时传的是单独的
preview,等于Viewport根本没被用上。 - 比例参数搞反了:你写的
Rational(9, 16)是9:16竖屏比例,如果需求是16:9横屏预览,这个参数完全错了。 - 多UseCase比例没对齐:ImageCapture、VideoCapture这些用例没设置匹配的比例,高分辨率设备的相机驱动会优先选高分辨率但比例不匹配的尺寸,直接导致预览拉伸或裁剪。
修复后的完整代码
cameraExecutor = Executors.newSingleThreadExecutor() imgCaptureExecutor = Executors.newSingleThreadExecutor() cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener({ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() // 按需替换比例:16:9=Rational(16,9),4:3=Rational(4,3),1:1=Rational(1,1) val targetAspectRatio = Rational(16, 9) // 配置Preview,先把比例对齐 val preview = Preview.Builder() .setTargetAspectRatio(targetAspectRatio) .build() .also { it.setSurfaceProvider(binding.cameraViewer.surfaceProvider) } // ImageCapture也要设置相同比例 imageCapture = ImageCapture.Builder() .setTargetAspectRatio(targetAspectRatio) .build() // VideoCapture必须对齐比例,不然和其他用例冲突 val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD) ) val recorder = Recorder.Builder() .setExecutor(cameraExecutor) .setQualitySelector(qualitySelector) .setTargetAspectRatio(targetAspectRatio) // 新增比例对齐 .build() videoCapture = VideoCapture.withOutput(recorder) // ImageAnalysis同样要对齐比例 val imageAnalysis = ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .setTargetAspectRatio(targetAspectRatio) .build() // 正确创建Viewport,适配不同版本的屏幕旋转 val viewPort = ViewPort.Builder( targetAspectRatio, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display?.rotation ?: Surface.ROTATION_0 } else { windowManager.defaultDisplay.rotation } ).build() try { cameraProvider.unbindAll() // 把所有用例放进UseCaseGroup val useCaseGroup = UseCaseGroup.Builder() .addUseCase(preview) .addUseCase(imageCapture!!) .addUseCase(videoCapture!!) .addUseCase(imageAnalysis) .setViewPort(viewPort) .build() // 重点:绑定UseCaseGroup到生命周期,不是单独的preview! val camera = cameraProvider.bindToLifecycle( this, cameraSelector, useCaseGroup ) } catch (exc: Exception) { Log.e(TAG, "Use case binding failed", exc) } }, ContextCompat.getMainExecutor(this))
核心修复点
- 绑定UseCaseGroup而非单个Preview:这是Viewport生效的关键,之前的操作等于白配置了Viewport。
- 所有用例统一比例:Preview、ImageCapture、VideoCapture、ImageAnalysis必须用相同的
targetAspectRatio,避免相机驱动选择冲突的尺寸。 - 修正比例参数:根据实际需求选对Rational值,比如16:9就用
Rational(16,9),别搞反横竖。 - 适配旧版本旋转角度:Android R以下用
windowManager.defaultDisplay.rotation获取正确旋转,避免比例因旋转错误乱掉。
额外优化
对高分辨率设备,还可以指定具体分辨率,比如强制1080P,进一步保证预览尺寸匹配:
Preview.Builder() .setTargetAspectRatio(targetAspectRatio) .setTargetResolution(Size(1920, 1080)) .build()
如果要动态切换比例,直接重新创建所有用例和UseCaseGroup,再重新绑定生命周期就行。
内容的提问来源于stack exchange,提问作者Jaydeep sinroja
相关产品推荐
相关产品推荐

