Implementación de PhotoPreviewScreen en aplicaciones Android
Clase 28 de 33 • Curso de Android: Integración de APIs nativas
Resumen
La captura y previsualización de imágenes desde la cámara en aplicaciones Android con Jetpack Compose es una funcionalidad práctica y sencilla de implementar. Aquí encontrarás cómo usar un composable para mostrar imágenes previas antes de guardarlas o descartarlas.
¿Cómo crear un PhotoPreviewScreen por medio de Jetpack Compose?
Jetpack Compose permite estructurar interfaces eficaces rápidamente. Para desplegar una imagen obtenida por la cámara, utilizaremos un composable llamado PhotoPreviewScreen. Esta vista recibe:
- Un ByteArray con la imagen capturada.
- Un lambda llamado OnSaved, encargado de guardar la foto.
- Un lambda llamado OnCanceled, para cancelar la operación y volver a la vista de captura.
Para convertir el ByteArray en algo visualizable, utilizamos una función de extensión previamente creada que convierte este array en una imagen tipo Bitmap:
bytesArray.AsImageBitmap()
¿Qué lógica aplica a nuestra CameraScreenRoot?
En la pantalla principal denominada CameraScreenRoot, el primer paso es vincularse con un ViewModel:
val UIState by ViewModel.UIState.collectAsState()
val previewFoto by ViewModel.PreviewFoto.collectAsState()
La interfaz se compone principalmente de un contenedor (Box) con tamaño completo que muestra una imagen previsualizada si está disponible:
- Cuando exista una imagen previa, desplegar PhotoPreviewScreen, usando los datos obtenidos del ViewModel.
PhotoPreviewScreen(
PhotoBytes = previewFoto,
OnSaved = { ViewModel.Action(CameraIntent.SavePhoto) },
OnCancel = { ViewModel.Action(CameraIntent.CancelPreview) }
)
- En caso contrario, mostrar la vista principal de captura (CameraScreen).
¿Cómo rotar correctamente la imagen capturada?
Cuando se toma una foto a través de la API de cámara, por defecto su orientación viene girada 90 grados, lo cual requiere una transformación adicional. Esto se logra aplicando una matriz de rotación en grados provista por la cámara:
val matrix = Matrix().apply {
postRotate(imageProxy.imageInfo.rotationDegrees.toFloat())
}
val rotatedBitmap = Bitmap.createBitmap(
imageProxy.toBitmap(),
0, 0,
imageProxy.width,
imageProxy.height,
matrix,
true
)
ViewModel.Action(CameraIntent.TakenPicture(rotatedBitmap.toByteArray()))
Luego, este bitmap girado convertido en ByteArray es el que se envía al ViewModel para la previsualización.
¿Cómo implementar definitivamente esta solución?
En la actividad principal (MainActivity) se sustituye la pantalla básica de captura por la que incluye previsualización:
CameraScreenRoot()
Esta lógica pone en marcha la captura y muestra visual inmediata de las fotos capturadas, permitiendo aceptar o rechazar cada imagen tomada según lo que el usuario decida.
¿Qué permisos necesito solicitar?
Como paso adicional, pero indispensable, están los permisos que garantizan la operación adecuada y segura de la cámara. El manejo de permisos sigue el mismo patrón utilizado previamente en pantallas como MapScreen. Revisa dicho procedimiento paso a paso y practica integrándolo aquí, aprovechando los recursos de referencia, como el repositorio del proyecto, en caso de dudas.
¡Anímate a implementar esta útil funcionalidad en tu app y compártenos cómo te fue!