To provide you as simple example as possible, I will use CameraXBasic repository on Github. My goal is to implement tap to focus feature - when user taps on the preview, the camera should focus in the indicated point. I will skip the camera configuration, as the mentioned repository is an official sample and we can assume that it was implemented according to the documentation.
So in order to intercept user taps I added this part of code:
viewFinder.setOnTouchListener { v, event ->
if (event.action != MotionEvent.ACTION_UP) {
return@setOnTouchListener true
}
val factory = SurfaceOrientedMeteringPointFactory(
v.width.toFloat(),
v.height.toFloat()
)
val focusPoint = factory.createPoint(event.x, event.y)
val focusAction = FocusMeteringAction.Builder(focusPoint).build()
camera?.cameraControl?.startFocusAndMetering(focusAction)
return@setOnTouchListener true
}
It's worth mentioning, that above method is based on this blog. Everything works fine, except the camera focuses on wrong objects. E.g. we have two objects behind the camera:
-------
| | -----
| | | |
| A | | B |
| | | |
| | -----
-------
As you can imagine, object A is closer to the device than object B. When I tap on the A object, camera focuses on the B object. And conversely, when I tap on the B object, camera focuses on the A object. It looks like library was using not the event.x value, but v.width - event.x value.
To check this behavior, you can add code from this question to the provided sample in viewFinder.post { /* */ } method.
Update
As mentioned in this answer, the issue may be related to PreviewView which I was using. When creating the focus point we have to (at least for now) translate the point to PreviewView rotation. E.g. when device is in vertical position, just use this transformation: factory.createPoint(event.y, v.width - event.x).