LazyRow — это composable-функция в Jetpack Compose для создания горизонтальных списков с ленивой загрузкой элементов. В отличие от Row, LazyRow создаёт только видимые элементы и переиспользует их при горизонтальной прокрутке. По данным Google Android Documentation, 2025, LazyRow является горизонтальным аналогом LazyColumn и эффективен для каруселей, галерей и горизонтальных меню в мобильных приложениях.
Главное
LazyRow — это composable-функция, реализующая горизонтальный прокручиваемый список с ленивой загрузкой элементов. В отличие от Row, который отрисовывает все дочерние элементы одновременно, LazyRow создаёт только элементы, видимые в области просмотра.
LazyRow работает по тому же принципу, что и LazyColumn, но располагает элементы горизонтально. При прокрутке влево или вправо вышедшие из области просмотра элементы переиспользуются для отображения новых. Это критически важно для галерей с большим количеством изображений или длинных списков категорий.
По данным Android Developers Blog, 2024, LazyRow использует ту же архитектуру LazyList, что и LazyColumn, включая LazyListState, механизм переиспользования через Pool и поддержку разных типов элементов. Максимальная эффективность достигается при использовании фиксированной высоты элементов.
LazyRow принимает параметры modifier, state, contentPadding, reverseLayout, horizontalArrangement и verticalAlignment. Содержимое задаётся через DSL-функции items и item, аналогично LazyColumn.
@Composable
fun SimpleLazyRow() {
val items = (1..50).toList()
LazyRow(
modifier = Modifier.fillMaxWidth().height(100.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(start = 16.dp, end = 16.dp)
) {
items(items) { item ->
Box(
modifier = Modifier.size(80.dp).background(Color.Gray)
) {
Text(text = "$item", modifier = Modifier.align(Alignment.Center))
}
}
}
}
horizontalArrangement управляет распределением элементов по горизонтальной оси внутри LazyRow. Доступны те же значения Arrangement, что и в Row: Start, Center, End, SpaceBetween, SpaceEvenly, SpaceAround и spacedBy с кастомным отступом.
contentPadding добавляет отступы по краям контейнера LazyRow. В отличие от Modifier.padding, contentPadding учитывается при прокрутке: первый элемент будет иметь отступ от левого края, последний — от правого. По данным Material Design Guidelines, 2025, contentPadding обязателен для каруселей и галерей, чтобы первый и последний элементы не прилипали к краю экрана.
verticalAlignment выравнивает элементы по вертикали внутри LazyRow. По умолчанию используется Alignment.Top. Для центрирования элементов разной высоты используйте Alignment.CenterVertically, что полезно для каруселей с изображениями разных пропорций.
| Параметр | Описание | Значение по умолчанию |
|---|---|---|
| horizontalArrangement | Распределение элементов по горизонтали | Arrangement.Start |
| contentPadding | Отступы по краям контейнера | PaddingValues(0.dp) |
| verticalAlignment | Выравнивание по вертикали | Alignment.Top |
| reverseLayout | Обратный порядок элементов | false |
| userScrollEnabled | Разрешение прокрутки пользователем | true |
LazyListState для LazyRow работает идентично LazyColumn: он отслеживает первый видимый элемент, смещение и общую позицию прокрутки. Состояние создаётся через rememberLazyListState() и передаётся в параметр state.
Программное управление прокруткой LazyRow осуществляется теми же методами: animateScrollToItem для плавной анимации и scrollToItem для мгновенной прокрутки. Оба вызываются внутри корутины. Это полезно для каруселей с кнопками "Влево/Вправо" или для автоматической прокрутки.
По данным Android Developers, 2024, LazyRow также поддерживает SnapFlingBehavior — поведение при резкой прокрутке, которое останавливается на ближайшем элементе, а не между элементами. Это создаёт эффект "прилипания" к элементу, привычный для каруселей и галерей.
@Composable
fun CarouselWithSnap() {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
val items = listOf("A", "B", "C", "D", "E")
Column {
LazyRow(
state = listState,
flingBehavior = SnapFlingBehavior(listState),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(items) { item ->
Card(modifier = Modifier.width(150.dp)) {
Text(text = item, modifier = Modifier.padding(16.dp))
}
}
}
Row(modifier = Modifier.fillMaxWidth()) {
Button(onClick = {
scope.launch {
listState.animateScrollToItem(0)
}
}) { Text("To start") }
}
}
}
Первый пример — LazyRow для галереи изображений с превью. Каждый элемент представляет собой Box с изображением и подписью. LazyRow эффективно обрабатывает десятки и сотни изображений, загружая только видимые.
@Composable
fun ImageGallery(images: List<String>) {
LazyRow(
contentPadding = PaddingValues(start = 16.dp, end = 16.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
items(images, key = { it }) { url ->
AsyncImage(
model = url,
contentDescription = "Image",
modifier = Modifier.size(120.dp)
)
}
}
}
Второй пример — LazyRow для списка категорий с иконками. Категории отображаются в виде чипов, и пользователь может прокручивать их горизонтально. LazyRow с spacedBy и contentPadding создаёт отступы между категориями и по краям.
@Composable
fun CategoryChips(categories: List<String>) {
LazyRow(
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(categories, key = { it }) { category ->
AssistChip(
onClick = {},
label = { Text(category) }
)
}
}
}
Выбор между LazyRow и Row зависит от количества элементов. Row подходит для 5–10 элементов, которые всегда видны на экране. LazyRow обязателен, когда элементов много или их количество динамическое.
Row отрисовывает все элементы сразу, что приводит к задержкам при большом количестве элементов. LazyRow отрисовывает только видимые, что делает его предпочтительным для списков с прокруткой. По данным Android Developers Blog, 2024, порог перехода — примерно 10 элементов: если элементов больше, используйте LazyRow.
LazyRow также поддерживает анимации, SnapFlingBehavior и группировку через разделители, что делает его более гибким для сложных интерфейсов. Row проще и не требует LazyListState, но не оптимизирован для длинных списков.
Часто задаваемые вопросы
LazyRow прокручивается горизонтально и располагает элементы слева направо, а LazyColumn — вертикально сверху вниз. Оба используют одинаковые принципы ленивой загрузки, LazyListState и DSL-функции items.
Передайте SnapFlingBehavior(listState) в параметр flingBehavior LazyRow. SnapFlingBehaviour заставляет LazyRow останавливаться на ближайшем элементе, а не между элементами, что создаёт эффект прилипания для каруселей.
Отслеживайте последний видимый элемент через LazyListState.layoutInfo и подгружайте новые данные, когда последний элемент приближается к концу списка. Для циклической прокрутки используйте кастомную реализацию с дублированием элементов.
Да, LazyRow можно вкладывать в LazyColumn. Это стандартный паттерн для создания сложных страниц с горизонтальными каруселями внутри вертикального списка. Каждый LazyRow должен иметь фиксированную высоту для корректной работы.
Используйте LazyListState.layoutInfo.visibleItemsInfo и сравните индекс последнего видимого элемента с общим количеством минус один. Когда эти значения совпадают, LazyRow находится в конце списка.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также