Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

243
Views
¿Cómo puedo usar CameraView con Jetpack Compose?

Actualmente no hay equivalente a CameraView (y PreviewView) en Compose. ¿Es posible envolverlo y mostrarlo en un diseño de composición?

over 4 years ago · Hanz Gallego
4 answers
Answer question

0

Por el momento, no hay ninguna función Composable oficial para CameraX, por lo que tenemos que inflar la vista de Android heredada dentro de Composer.

Para lograr eso podemos usar la función composable de AndroidView , acepta dos parámetros

  • @param resId El id del recurso de diseño que se va a inflar.
  • @param postInflationCallback La devolución de llamada que se invocará después de inflar el diseño.

y para acceder al ciclo de vida y contexto usamos los ambients

 val lifecycleOwner = LifecycleOwnerAmbient.current val context = ContextAmbient.current

Como tenemos todo lo que necesitamos hagámoslo:

Crear un diseño camera_host.xml

 <?xml version="1.0" encoding="utf-8"?> <androidx.camera.view.PreviewView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/previewView" android:layout_width="match_parent" android:layout_height="match_parent" />

e inflarlo usando la función AndroidView .

 @Composable fun SimpleCameraPreview() { val lifecycleOwner = LifecycleOwnerAmbient.current val context = ContextAmbient.current val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) } AndroidView(resId = R.layout.camera_host) { inflatedLayout -> //You can call // findViewById<>() and etc ... on inflatedLayout // here PreviewView is the root of my layout so I just cast it to // the PreviewView and no findViewById is required cameraProviderFuture.addListener(Runnable { val cameraProvider = cameraProviderFuture.get() bindPreview( lifecycleOwner, inflatedLayout as PreviewView /*the inflated layout*/, cameraProvider) }, ContextCompat.getMainExecutor(context)) } } fun bindPreview( lifecycleOwner: LifecycleOwner, previewView: PreviewView, cameraProvider: ProcessCameraProvider ) { var preview: Preview = Preview.Builder().build() var cameraSelector: CameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build() preview.setSurfaceProvider(previewView.createSurfaceProvider()) var camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) }
 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { SimpleCameraPreview() } } }
over 4 years ago · Hanz Gallego Report

0

Todavía no hay Componible de CameraX. Necesita usar AndroidView para crear uno.

Ejemplo actualizado para Compose 1.0.0-beta02:

 @Composable fun CameraPreview( modifier: Modifier = Modifier, cameraSelector: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA, scaleType: PreviewView.ScaleType = PreviewView.ScaleType.FILL_CENTER, ) { val lifecycleOwner = LocalLifecycleOwner.current AndroidView( modifier = modifier, factory = { context -> val previewView = PreviewView(context).apply { this.scaleType = scaleType layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) // Preview is incorrectly scaled in Compose on some devices without this implementationMode = PreviewView.ImplementationMode.COMPATIBLE } val cameraProviderFuture = ProcessCameraProvider.getInstance(context) cameraProviderFuture.addListener({ val cameraProvider = cameraProviderFuture.get() // Preview val preview = Preview.Builder() .build() .also { it.setSurfaceProvider(previewView.surfaceProvider) } try { // Must unbind the use-cases before rebinding them. cameraProvider.unbindAll() cameraProvider.bindToLifecycle( lifecycleOwner, cameraSelector, preview ) } catch (exc: Exception) { Log.e(TAG, "Use case binding failed", exc) } }, ContextCompat.getMainExecutor(context)) previewView }) }
over 4 years ago · Hanz Gallego Report

0

Creé una biblioteca para usar CameraX en Jetpack Compose. Puede ser útil hasta que salga una biblioteca oficial.

https://github.com/skgmn/CameraXX

En su build.gradle, (requiere token de acceso personal de GitHub)

 implementation "com.github.skgmn:cameraxx-composable:0.3.0"

Firma de método componible

 CameraPreview( modifier: Modifier = Modifier, cameraSelector: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA, preview: Preview?, imageCapture: ImageCapture? = null, imageAnalysis: ImageAnalysis? = null )

Puede omitir el parámetro de preview para usar la instancia de Preview predeterminada.

Un ejemplo

 class MainViewModel : ViewModel() { val imageCapture = ImageCapture.Builder().build() } @Composable fun Main() { val viewModel: MainViewModel = viewModel() val imageCapture by remember { viewModel.imageCapture } CameraPreview(Modifier.fillMaxSize(), imageCapture) }
over 4 years ago · Hanz Gallego Report

0

Este es mi fragmento (basado en la respuesta de Sean), que también maneja el estado de la antorcha y la disposición de los recursos y agrega un enfoque en la lógica del toque. Dependencias:

 implementation 'androidx.camera:camera-camera2:1.1.0-alpha11' implementation 'androidx.camera:camera-view:1.0.0-alpha31' implementation 'androidx.camera:camera-lifecycle:1.1.0-alpha11' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0-RC'
 @Composable fun CameraPreview( modifier: Modifier = Modifier, cameraSelector: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA, implementationMode: PreviewView.ImplementationMode = PreviewView.ImplementationMode.COMPATIBLE, scaleType: PreviewView.ScaleType = PreviewView.ScaleType.FILL_CENTER, imageAnalysis: ImageAnalysis? = null, imageCapture: ImageCapture? = null, preview: Preview = remember { Preview.Builder().build() }, enableTorch: Boolean = false, focusOnTap: Boolean = false ) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current val cameraProvider by produceState<ProcessCameraProvider?>(initialValue = null) { value = ProcessCameraProvider.getInstance(context).await() } // TODO: add cameraSelector val camera = remember(cameraProvider) { cameraProvider?.let { it.unbindAll() it.bindToLifecycle( lifecycleOwner, cameraSelector, *listOfNotNull(imageAnalysis, imageCapture, preview).toTypedArray() ) } } LaunchedEffect(camera, enableTorch) { camera?.let { if (it.cameraInfo.hasFlashUnit()) { it.cameraControl.enableTorch(enableTorch).await() } } } DisposableEffect(Unit) { onDispose { cameraProvider?.unbindAll() } } AndroidView( modifier = modifier.pointerInput(camera, focusOnTap) { if (!focusOnTap) return@pointerInput detectTapGestures { val meteringPointFactory = SurfaceOrientedMeteringPointFactory( size.width.toFloat(), size.height.toFloat() ) val meteringAction = FocusMeteringAction.Builder( meteringPointFactory.createPoint(it.x, it.y), FocusMeteringAction.FLAG_AF ).disableAutoCancel().build() camera?.cameraControl?.startFocusAndMetering(meteringAction) } }, factory = { _ -> PreviewView(context).also { it.scaleType = scaleType it.implementationMode = implementationMode preview.setSurfaceProvider(it.surfaceProvider) } } ) }
over 4 years ago · Hanz Gallego Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!