Serie Android desde cero · 2
En la primera entrada de la serie instalamos Android Studio, creamos un proyecto con Jetpack Compose y pusimos un saludo en pantalla. Fue un buen comienzo, pero una app real necesita más que una línea de texto. Hoy vamos a dar el siguiente paso: diseñar tu primera pantalla de verdad, con texto, una imagen, un botón y todo bien acomodado.
Vamos a construir una tarjeta de perfil sencilla. Es un ejercicio que uso mucho en mis clases porque toca las piezas que vas a usar en casi cualquier pantalla: cómo apilar elementos, cómo ponerlos uno al lado del otro y cómo darles espacio para que respiren.
Antes de empezar
Usa el mismo proyecto de la primera parte. Si no lo tienes, crea uno nuevo con la plantilla Empty Activity, que ya viene lista para Compose. Todo lo que vamos a escribir va en MainActivity.kt, debajo de la clase MainActivity.
Un consejo: cuando Android Studio marque algo en rojo, pon el cursor encima y presiona Alt + Enter (o Option + Enter en Mac). Casi siempre falta un import, y el editor lo agrega por ti.
Las tres piezas básicas: Column, Row y Box
En Compose no dibujas la pantalla en un archivo XML. La describes con funciones, y para acomodar elementos usas tres contenedores:
- Column: pone los elementos uno debajo del otro, como una lista vertical.
- Row: los pone uno al lado del otro, en horizontal.
- Box: los pone uno encima del otro, en capas. Sirve, por ejemplo, para poner un texto sobre una imagen.
Con esas tres piezas, combinadas entre sí, puedes armar prácticamente cualquier diseño. Una pantalla compleja casi siempre es una Column que tiene Rows adentro, y así sucesivamente.
Tu primera Column
@Composable
fun Perfil() {
Column {
Text(text = "David")
Text(text = "Desarrollador Android")
Text(text = "Managua, Nicaragua")
}
}
Pon tus propios datos y ejecuta la app. Vas a ver los tres textos apilados en la esquina superior. Funciona, pero se ve apretado. Ahí entra el siguiente concepto.
Modifier: tamaño, espacio y color
Casi todos los elementos de Compose reciben un parámetro llamado modifier. Con él cambias el tamaño, el relleno, el fondo, los bordes y muchas cosas más. Los modificadores se encadenan, y el orden importa: se aplican de afuera hacia adentro.
@Composable
fun Perfil() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "David", fontSize = 28.sp, fontWeight = FontWeight.Bold)
Spacer(modifier = Modifier.height(4.dp))
Text(text = "Desarrollador Android")
Text(text = "Managua, Nicaragua", color = Color.Gray)
}
}
Esto es lo que cambió:
fillMaxSize()hace que la Column ocupe toda la pantalla.padding(24.dp)deja un margen interno. La unidaddpse adapta a la densidad de cada pantalla, así que tu diseño se ve parecido en cualquier teléfono.horizontalAlignmentyverticalArrangementcentran el contenido.Spaceragrega un espacio vacío entre dos elementos. Es la forma más simple de separar cosas.- Para el texto, el tamaño se mide en
sp, que respeta el tamaño de letra que la persona eligió en su teléfono.
Agrega una imagen
Copia una imagen cuadrada a la carpeta res/drawable de tu proyecto, por ejemplo avatar.png. El nombre debe ir en minúsculas y sin espacios. Luego la muestras así:
Image(
painter = painterResource(id = R.drawable.avatar),
contentDescription = "Foto de perfil",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(120.dp)
.clip(CircleShape)
)
El modificador clip(CircleShape) recorta la imagen en forma de círculo, y ContentScale.Crop hace que llene el espacio sin deformarse. No te saltes el contentDescription: es lo que lee el lector de pantalla a las personas con discapacidad visual.
Pon elementos en fila con Row
Ahora vamos a agregar dos datos uno al lado del otro, como si fueran estadísticas del perfil. Para eso usamos una Row:
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Dato(numero = "12", etiqueta = "Proyectos")
Dato(numero = "4", etiqueta = "Cursos")
}
@Composable
fun Dato(numero: String, etiqueta: String) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = numero, fontSize = 20.sp, fontWeight = FontWeight.Bold)
Text(text = etiqueta, color = Color.Gray)
}
}
Fíjate en algo importante: creé una función Dato y la usé dos veces. Esa es la gran idea de Compose. En lugar de repetir código, creas piezas pequeñas y las reutilizas. Los números son de ejemplo; pon los que quieras.
Un botón que responde
Por último, un botón. Por ahora solo va a mostrar un mensaje corto cuando lo toques:
val contexto = LocalContext.current
Button(
onClick = {
Toast.makeText(contexto, "¡Hola!", Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Contactar")
}
El contenido del botón va entre llaves, igual que en una Column. Eso significa que adentro podrías poner un ícono y un texto en una Row, por ejemplo.
La pantalla completa
Junta todo dentro de la Column principal, en este orden: la imagen, un Spacer, los textos, otro Spacer, la Row con los datos y el botón al final. Llama a Perfil() desde setContent, dentro del tema de tu app, y ejecuta. Ya tienes una pantalla con estructura de verdad.
Si quieres ver los cambios sin ejecutar la app cada vez, agrega una vista previa:
@Preview(showBackground = true)
@Composable
fun PerfilPreview() {
MiPrimeraAppTheme {
Perfil()
}
}
La vista previa aparece en el panel Split o Design de Android Studio y se actualiza mientras escribes. Te ahorra mucho tiempo.
Errores comunes
- Todo aparece amontonado arriba: te faltó
fillMaxSize()o la alineación en la Column. - La imagen no aparece: revisa que el archivo esté en
res/drawabley que el nombre no tenga mayúsculas, espacios ni guiones. - El padding no hace lo que esperas: recuerda que el orden de los modificadores importa. No es lo mismo poner el fondo antes o después del padding.
Lo que sigue
Tu pantalla ya se ve bien, pero todavía no cambia: si tocas el botón, los datos siguen iguales. Para que la interfaz reaccione necesitas manejar el estado, y ese es justo el tema de la siguiente entrada de la serie: StateFlow en Jetpack Compose con ViewModel. Después podrás seguir con la navegación entre pantallas y con Room para guardar datos en el teléfono.
Mi recomendación: antes de avanzar, cambia esta tarjeta. Prueba otros colores, agrega un tercer dato, mueve la imagen a la izquierda con una Row. Equivocarte con tus propias manos es la forma más rápida de entender cómo funcionan los contenedores.
Conclusión
Column, Row, Box y los modificadores son la base de cualquier pantalla en Compose. Si entiendes cómo se combinan, el resto es práctica. Hoy pasaste de un texto suelto a una pantalla con imagen, datos y un botón, y eso ya es mucho.
Si prefieres aprender con videos y ejercicios guiados, en mi curso Jetpack Compose: la nueva era de las UI en Android vemos esto con mucho más detalle, y aquí están todos mis cursos. Y si te trabas en algún paso, escríbeme en redes como davidgbdev.



Deja una respuesta