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

关于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 08:45:06