如何在 CameraX 中镜像 PreviewView?
How to mirror the PreviewView in CameraX?
免责声明:我知道 this question 的存在,但它目前尚未解决,我正在尝试提供额外的信息,而不是用无用的答案污染那个不会'反正解决不了问题
我有一个自定义设备,它的前置摄像头默认是镜像的,所以我想正常显示预览,我需要水平翻转PreviewView的内容,但是我卡住了。过去其他人建议使用 PreviewView#setScaleX(-1)
,但它要么根本不起作用,要么需要在代码中非常特定的点调用,我还没有找到。
下面的代码是官方CameraXBasic例子中CameraFragment.kt
的简化版;我在已经厌倦了调用 viewFinder.scaleX = -1f
但没有成功的地方添加了评论。老实说,我真的不认为这个地方有什么不同,因为如果我用 1 以外的任何值调用它,它在 scaleX
和 scaleY
上都能正常工作,但 它总是忽略负号 所以它永远不会翻转。
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
}
根据实现类型(COMPATIBLE
vs PERFORMANCE
)和设备,PreviewView
可以使用 TextureView
或 SurfaceView
,在你的情况我假设PreviewView
正在使用SurfaceView
,你可以通过访问PreviewView
的第一个子视图(View.getChildAt(0)
)来确认这一点。
TextureView
与任何其他 View
一样,这就是为什么当 PreviewView
使用它时,将其 scaleX 设置为 -1 应该反映显示的预览。创建布局后,您可以调用 PreviewView.setScaleX(-1F)
(例如,在 onViewCreated()
中)。
对于SurfaceView
,这有点棘手,因为Surface
和View
在某些方面是独立的: Surface
放置在包含 View
的 window 后面,视图层次结构通过在 window 中打孔来正确处理整个布局以显示 SurfaceView
的Surface
。这或许可以解释为什么镜像内容 SurfaceView
显示是不可能的,尽管我不确定为什么放大(scaleX 设置为值 > 1)和缩小(scaleX 设置为 0 到 1 之间的值)仍然有效。
免责声明:我知道 this question 的存在,但它目前尚未解决,我正在尝试提供额外的信息,而不是用无用的答案污染那个不会'反正解决不了问题
我有一个自定义设备,它的前置摄像头默认是镜像的,所以我想正常显示预览,我需要水平翻转PreviewView的内容,但是我卡住了。过去其他人建议使用 PreviewView#setScaleX(-1)
,但它要么根本不起作用,要么需要在代码中非常特定的点调用,我还没有找到。
下面的代码是官方CameraXBasic例子中CameraFragment.kt
的简化版;我在已经厌倦了调用 viewFinder.scaleX = -1f
但没有成功的地方添加了评论。老实说,我真的不认为这个地方有什么不同,因为如果我用 1 以外的任何值调用它,它在 scaleX
和 scaleY
上都能正常工作,但 它总是忽略负号 所以它永远不会翻转。
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
}
根据实现类型(COMPATIBLE
vs PERFORMANCE
)和设备,PreviewView
可以使用 TextureView
或 SurfaceView
,在你的情况我假设PreviewView
正在使用SurfaceView
,你可以通过访问PreviewView
的第一个子视图(View.getChildAt(0)
)来确认这一点。
TextureView
与任何其他 View
一样,这就是为什么当 PreviewView
使用它时,将其 scaleX 设置为 -1 应该反映显示的预览。创建布局后,您可以调用 PreviewView.setScaleX(-1F)
(例如,在 onViewCreated()
中)。
对于SurfaceView
,这有点棘手,因为Surface
和View
在某些方面是独立的: Surface
放置在包含 View
的 window 后面,视图层次结构通过在 window 中打孔来正确处理整个布局以显示 SurfaceView
的Surface
。这或许可以解释为什么镜像内容 SurfaceView
显示是不可能的,尽管我不确定为什么放大(scaleX 设置为值 > 1)和缩小(scaleX 设置为 0 到 1 之间的值)仍然有效。