如何在 CameraX 中镜像 PreviewView?

5

免责声明:我知道存在这个问题,但它目前没有得到解决,我试图提供额外的信息,而不是用无用的答案污染那个问题。

我有一个默认镜像的前置相机的自定义设备,所以我想正常显示预览,并且需要水平翻转PreviewView的内容,但我卡住了。过去其他人曾经建议使用PreviewView#setScaleX(-1),但它要么根本不起作用,要么需要在代码中的非常特定的位置调用,但我还没有找到这个位置。

下面的代码是官方CameraXBasic示例中的CameraFragment.kt的简化版本;我已经尝试过在旁边加上注释viewFinder.scaleX = -1f,但没有成功。老实说,我真的不认为位置有什么区别,因为如果我使用除1之外的任何值调用它,都可以使用scaleXscaleY正常工作,但它总是忽略负号,所以它从不翻转。

private lateinit var viewFinder: PreviewView

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    ...
    viewFinder = view.findViewById(R.id.view_finder)
    // HERE
    viewFinder.post {
        // HERE
        setupCamera()
    }
}

private fun setupCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
    cameraProviderFuture.addListener(Runnable {
        val cameraProvider = cameraProviderFuture.get()

        val cameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
            .build()

       val preview = Preview.Builder()
            .build()
            .also {
                // HERE
                it.setSurfaceProvider(viewFinder.surfaceProvider)
            }

       cameraProvider.unbindAll()

        try {
            cameraProvider.bindToLifecycle(this, cameraSelector, preview)
            // HERE
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
        // HERE
    }, ContextCompat.getMainExecutor(requireContext()))
    // HERE
}

这个问题有一个开放的问题:https://issuetracker.google.com/issues/169858170 - Glaucus
1个回答

8

根据实现类型(COMPATIBLE vs PERFORMANCE)和设备,在PreviewView中可以使用TextureViewSurfaceView,在您的情况下,我假设PreviewView正在使用SurfaceView,您可以通过访问PreviewView的第一个子视图(View.getChildAt(0))来确认。

TextureView就像任何其他View一样,因此当PreviewView使用它时,将其scaleX设置为-1应该可以镜像显示的预览。在创建布局后(例如,在onViewCreated()中),可以调用PreviewView.setScaleX(-1F)

对于SurfaceView,有点棘手,因为SurfaceView在某些方面是独立的: Surface位于包含View的窗口后面,并且View层次结构通过在窗口中打洞正确处理整个布局以显示SurfaceViewSurface。这可能解释了为什么不能镜像显示SurfaceView显示的内容,尽管我不确定为什么缩放(scaleX设置为值> 1)和缩小(scaleX设置为介于0和1之间的值)仍然有效。


该设备运行在Android 7.1上,记录“viewFinder.getChildAt(0)”显示为“null”。 “scaleX”设置为-1,现在它可以工作了吗?但是我刚刚在我的Android 10手机上尝试了这个应用程序,尽管预览仍未翻转,但我得到了相同的结果。我不知道为什么。 - rdxdkr
1
仅在预览已启动后调用getChildAt(0) - Husayn Hakeem
你的意思是在调用 bindToLifecycle() 之后?仍然得到 null - rdxdkr
1
不,调用binToLifecycle()后预览不会立即开始。您可以使用PreviewView.getPreviewStreamState()并等待分派STREAMING状态。您还可以使用任何其他方法,在预览开始后才调用该方法,例如在PreviewView上设置单击侦听器,当您看到预览已启动时单击它,在单击侦听器内部记录其第一个子项。 - Husayn Hakeem
2
我在stackoverflow上发布了一个新问题,详细说明了我要实现的内容。我开始使用CameraX是因为它应该需要最少的工作量,既可以使用相机,也可以调用MLKit API,但由于这些小问题,我不再100%确定。 - rdxdkr
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接