Reputation:
I was trying to use a CameraX PreviewView
inside of a Composable
via AndroidView
, but the preview is stretched and the right half is clipped as you can see in the screenshot.
Nevertheless the view seems to occupy the correct space.
This problem only occurs in portrait mode.
I was able to reproduce the problem on two cell phones and in the emulator so I doubt it is hardware specific.
I have tried different scale types, but that does not seem to affect the stretching. I would report a bug, but I am not sure whether this is a bug in compose or cameraX.
See the code I use below:
package com.example.camerapreview
import android.Manifest
import android.graphics.Color
import android.os.Bundle
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.LinearLayout
import androidx.activity.ComponentActivity
import androidx.activity.compose.registerForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.camera.core.AspectRatio.RATIO_16_9
import androidx.camera.core.CameraSelector
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import com.example.pointergun.ui.theme.PointerGunTheme
import com.google.common.util.concurrent.ListenableFuture
import androidx.camera.core.Preview
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
setContent {
PointerGunTheme {
Surface(color = MaterialTheme.colors.background) {
var isPermissionGranted by remember {
mutableStateOf<Boolean?>(null)
}
val launcher =
registerForActivityResult(contract = ActivityResultContracts.RequestPermission()) { isGranted ->
isPermissionGranted = isGranted
}
when (isPermissionGranted) {
true -> CameraPreview(cameraProviderFuture)
false -> Text("permission pls")
null -> Button(onClick = { launcher.launch(Manifest.permission.CAMERA) }) {
Text(text = "Start!")
}
}
}
}
}
}
}
fun bindPreview(
cameraProvider: ProcessCameraProvider,
lifecycleOwner: LifecycleOwner,
previewView: PreviewView,
) {
val preview: Preview = Preview.Builder()
.setTargetAspectRatio(RATIO_16_9)
.build()
val cameraSelector: CameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
preview.setSurfaceProvider(previewView.surfaceProvider)
var camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)
}
@Composable
fun CameraPreview(cameraProviderFuture: ListenableFuture<ProcessCameraProvider>) {
val lifecycleOwner = LocalLifecycleOwner.current
AndroidView(
factory = { context ->
PreviewView(context).apply {
setBackgroundColor(Color.GREEN)
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
scaleType = PreviewView.ScaleType.FILL_START
post {
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
bindPreview(
cameraProvider,
lifecycleOwner,
this,
)
}, ContextCompat.getMainExecutor(context))
}
}
}
)
}
Upvotes: 12
Views: 4421
Reputation: 2709
Need to set the implementation mode for the PreviewView
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
In your case :
PreviewView(context).apply {
setBackgroundColor(Color.GREEN)
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
scaleType = PreviewView.ScaleType.FILL_START
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
post {
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
bindPreview(
cameraProvider,
lifecycleOwner,
this,
)
}, ContextCompat.getMainExecutor(context))
}
}
Upvotes: 11