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

Jetpack Compose实现正方形相机预览时出现比例异常及UI重叠问题求助

Jetpack Compose实现正方形相机预览时出现比例异常及UI重叠问题求助

大家好,我目前在基于Jetpack Compose开发相机相关功能,需求是只使用传感器采集的图像中的正方形区域,所以希望在UI里显示正方形的相机预览,其他UI元素都放在预览区域之外。但实际运行后遇到了两个问题:

  • 预览区域显示为3:4的矩形,不是预期的正方形
  • 预览区域和下方的UI元素重叠了,而这些UI是按照正方形预览的布局逻辑来排列的

我尝试了以下代码,麻烦大家帮忙看看问题出在哪里:

MainActivity代码

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            MyApplicationTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Content(
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }
}

CameraPreview Composable

@Composable
fun CameraPreview() {
    val previewH = (LocalConfiguration.current.screenWidthDp).dp

    fun startCamera(context: Context, previewView: PreviewView) {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
        cameraProviderFuture.addListener({
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            // CameraSelector for back camera
            val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build()

            // Set up Preview use case
            val preview = Preview.Builder().build().also {
                it.surfaceProvider = previewView.surfaceProvider
            }

            try {
                // Unbind all use cases before rebinding
                cameraProvider.unbindAll()

                val viewPort = ViewPort.Builder(Rational(1,1), Surface.ROTATION_0)
                    .setScaleType(ViewPort.FILL_CENTER)
                    .build()
                val useGrp = UseCaseGroup.Builder()
                    .addUseCase(preview)
                    .addUseCase(ImageAnalysis.Builder().build())
                    .setViewPort(viewPort)
                    .build()

                // Bind the camera to the lifecycle and the Preview use case
                cameraProvider.bindToLifecycle(context as LifecycleOwner, cameraSelector, useGrp)
            } catch (exc: Exception) {
                Log.e("CameraXApp", "Use case binding failed", exc)
            }
        }, ContextCompat.getMainExecutor(context))
    }

    Box(modifier = Modifier.fillMaxWidth().height(previewH)) {
        AndroidView(
            modifier = Modifier.fillMaxSize()
                .onGloballyPositioned { c ->
                    Log.i("PREVIEW", "Androview size: ${c.size}")
                },
            factory = { context ->
                val screenWidth = Resources.getSystem().displayMetrics.widthPixels
                val previewView = PreviewView(context).apply {
                    scaleType = PreviewView.ScaleType.FILL_CENTER
                    layoutParams = ViewGroup.LayoutParams(
                        screenWidth,
                        screenWidth
                    )
                }
                //focusFactory = previewView.meteringPointFactory
                startCamera(context, previewView)
                previewView
            }
        )
    }
}

Content Composable

@Composable
fun Content(modifier: Modifier = Modifier) {
    val ctx = LocalContext.current
    val needPermission = remember {
        mutableStateOf(ContextCompat.checkSelfPermission(ctx, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
    }
    val CAMERA_PERMISSION_REQUEST_CODE = 101

    @Composable
    fun PermissionRequestUI() {
        Column(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Text("Camera permission is required to use this feature.")
            Button(onClick = {
                ActivityCompat.requestPermissions(
                    ctx as Activity,
                    arrayOf(Manifest.permission.CAMERA),
                    CAMERA_PERMISSION_REQUEST_CODE
                )
                needPermission.value = false
            }) {
                Text("Grant Permission")
            }
        }
    }

    if(needPermission.value) {
        PermissionRequestUI()
    } else {
        Column(modifier = modifier) {
            CameraPreview()
            Text("ABYR")
            Text("VALG")
            Text("qwert")
            Text("zxcv")
        }
    }
}

我已经尝试设置了ViewPort的比例为1:1,也把PreviewView的宽高都设为屏幕宽度,外层的Box高度也设置成了屏幕宽度的dp值,但还是没解决问题,希望大家能帮我找到问题所在,谢谢!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 10:32:59