LazyColumn es una función composable en Jetpack Compose para crear listas verticales con carga diferida de elementos. A diferencia de Column, LazyColumn crea y compone solo los elementos visibles en pantalla, reutilizándolos durante el desplazamiento. Según Google Android Documentation, 2025, LazyColumn es la herramienta principal para mostrar grandes conjuntos de datos en aplicaciones móviles gracias a su eficiente gestión de memoria.
Puntos clave
LazyColumn es una función composable que implementa una lista vertical desplazable con carga diferida. A diferencia de Column, que renderiza todos los hijos a la vez, LazyColumn crea solo los elementos que están dentro del área visible.
El mecanismo de carga diferida en LazyColumn se basa en la reutilización de elementos: cuando un elemento se oculta durante el desplazamiento, su composición y diseño pueden reutilizarse para un nuevo elemento mostrado. Esto ahorra memoria y tiempo de CPU, especialmente en listas largas.
Según Android Developers Blog, 2024, LazyColumn puede manejar eficientemente listas de decenas de miles de elementos sin una degradación significativa del rendimiento. Cada elemento en LazyColumn tiene una clave (key) que ayuda a Compose a identificar y preservar el estado del elemento cuando la lista cambia.
LazyColumn acepta los parámetros modifier, state, contentPadding, reverseLayout, verticalArrangement y horizontalAlignment. El contenido se define en un bloque lambda mediante las funciones DSL items e item.
@Composable
fun SimpleLazyColumn() {
val itemsList = (1..100).toList()
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(16.dp)
) {
items(itemsList) { item ->
Text(text = "Elemento $item")
}
}
}
El bloque DSL de LazyColumn proporciona las funciones items e item para agregar contenido. items acepta una colección de datos, una clave y una función fábrica para crear elementos. item agrega un único elemento estático a la lista.
itemsIndexed es una variante de items que pasa el índice del elemento además de los datos. Esto es útil cuando se necesita conocer la posición del elemento sin un cálculo separado. items(size) acepta solo el número de elementos y una fábrica sin vincularse a una colección.
El parámetro key en items identifica de forma única cada elemento. Según Material Design Guidelines, 2025, las claves mejoran el rendimiento al actualizar y animar elementos, ya que Compose puede rastrear el movimiento o cambio de un elemento específico por su clave.
La función items con contentType permite a LazyColumn optimizar la reutilización de elementos de diferentes tipos. En el siguiente ejemplo se usan encabezados de sección y filas normales en una sola lista.
@Composable
fun MixedItemsList() {
LazyColumn {
item {
Text(
text = "Encabezado",
style = MaterialTheme.typography.headlineMedium
)
}
items(
items = (1..20).toList(),
key = { it },
contentType = { "item" }
) { item ->
Text(text = "Fila $item")
}
}
}
LazyListState es un objeto de estado de LazyColumn que rastrea la posición actual de desplazamiento, el primer elemento visible y el desplazamiento. Se puede crear mediante rememberLazyListState() y pasarlo al parámetro state de LazyColumn.
LazyListState proporciona los métodos animateScrollToItem y scrollToItem para el desplazamiento programático a un elemento específico. animateScrollToItem crea una animación suave de desplazamiento, mientras que scrollToItem desplaza instantáneamente. Ambos métodos requieren ser llamados dentro de una corrutina en CompositionContext.
Según Android Developers, 2024, LazyListState también contiene layoutInfo, que proporciona información sobre los elementos visibles: sus índices, desplazamientos y tamaños. Esto es útil para implementar analíticas, seguimiento de vistas o desplazamiento infinito.
En este ejemplo, LazyColumn se controla mediante LazyListState. Un botón desplaza la lista al elemento con índice 50 con una animación suave.
@Composable
fun ScrollableList() {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
Column {
Button(
onClick = {
scope.launch {
listState.animateScrollToItem(50)
}
}
) {
Text("Desplazar a 50")
}
LazyColumn(state = listState) {
items((1..100).toList()) { item ->
Text(
text = "Elemento $item",
modifier = Modifier.padding(8.dp)
)
}
}
}
}
El factor clave de rendimiento de LazyColumn es el uso correcto de claves. Cada elemento debe tener una clave estable única mediante el parámetro key. Sin claves, Compose no puede reutilizar correctamente los elementos cuando los datos cambian, lo que provoca recomposición.
contentType le indica a LazyColumn qué elementos tienen el mismo tipo de diseño. Cuando dos elementos con el mismo contentType entran en el grupo de reciclaje, LazyColumn puede reutilizar su diseño sin recomposición. Según Android Developers Blog, 2024, contentType mejora el rendimiento entre un 30 y un 50% en listas con diferentes tipos de elementos.
Para LazyColumn, también es importante evitar parámetros inestables en las funciones fábrica. Cada vez que un parámetro de elemento cambia, Compose recompone ese elemento. Usar remember y derivedStateOf para valores estables reduce el número de recomposiciones.
| Factor | Impacto | Recomendación |
|---|---|---|
| Claves (key) | Crítico | Establezca siempre una clave estable única para items |
| contentType | Significativo | Indique el tipo de elemento para optimizar la reutilización |
| Tamaño de elementos | Moderado | Use tamaños fijos cuando sea posible |
| Listas anidadas | Crítico | Evite LazyColumn dentro de LazyColumn — use LazyVerticalGrid |
stickyHeader es una función DSL de LazyColumn que fija un encabezado de sección en la parte superior de la lista durante el desplazamiento. Cuando la siguiente sección llega a la parte superior, su encabezado reemplaza al actual. Este comportamiento es familiar para los usuarios de listas de contactos y calendarios.
stickyHeader acepta una clave y una función fábrica, similar a item. A diferencia de un elemento normal, stickyHeader permanece visible mientras se desplaza por el contenido de su sección. Cuando una sección se desplaza completamente, el encabezado de la siguiente sección empuja al anterior.
Según Material Design Guidelines, 2025, los sticky headers mejoran la navegación en listas largas y reducen la carga cognitiva del usuario. Para implementar un sticky header, simplemente envuelva un encabezado de sección en stickyHeader en la posición correcta respecto a los elementos items.
@Composable
fun SectionedList(sections: Map<String, List<String>>) {
LazyColumn {
sections.forEach { (header, items) ->
stickyHeader {
Text(
text = header,
modifier = Modifier.background(Color.White)
.padding(16.dp)
)
}
items(items) { item ->
Text(text = item, modifier = Modifier.padding(8.dp))
}
}
}
}
Preguntas frecuentes
Column renderiza todos los elementos a la vez y es adecuada para listas de hasta 20–30 elementos. LazyColumn crea solo los elementos visibles y los reutiliza durante el desplazamiento, lo que permite trabajar con miles de elementos sin pérdida de rendimiento.
Use Arrangement.spacedBy en el parámetro verticalArrangement o funciones items con un separador mediante índice. Para separadores complejos, agregue un item separado con Divider() entre los elementos de la lista.
LazyColumn se recompone automáticamente cuando cambia la colección de datos, si se utilizan claves estables. Los cambios detectados mediante mutableStateListOf o StateFlow provocan que solo los elementos modificados se redibujen.
No se recomienda anidar directamente LazyColumn dentro de LazyColumn — ambas tienen desplazamiento independiente, lo que crea conflictos de gestos. En su lugar, use un Column normal con LazyColumn dentro de una Section desplazable o LazyVerticalGrid para cuadrículas.
Use LazyListState.layoutInfo.visibleItemsInfo y compare el índice del último elemento visible con el número total de elementos. Para desplazamiento infinito, rastree cuándo el último elemento visible se acerca al final de la lista.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también