Если необходимо отобразить большое количество элементов (или список неизвестной длины), использование стандартных контейнеров как Column или Row может вызвать проблемы с производительностью, так как все вложенные элементы будут скомпонованы внутри контейнера независимо от того, видимы они или нет. Для более эффективной работы со вложенными компонентами Jetpack Compose предоставляет такие компоненты-контейнеры как LazyColumn и LazyRow. Они компонуют и добавляют только те элементы, которые видны в окне просмотра компонента. При прокрутке в контейнер компонуются новые элементы, а старые удаляются. При обратной прокрутке происходит повторная компоновка старых элементов. Собственно название контейнеров уже говорит о том, что они производят так называюмую lazy-загрузку (или ленивую загрузку), когда элементы загружаются не сразу, а по мере необходимости.
LazyColumn создает список с вертикальной прокруткой, а LazyRow создает список с горизонтальной прокруткой и имеет следующие параметры:
@Composable fun LazyColumn( modifier: Modifier = Modifier, state: LazyListState = rememberLazyListState(), contentPadding: PaddingValues = PaddingValues(0.dp), reverseLayout: Boolean = false, verticalArrangement: Arrangement.Vertical = if (!reverseLayout) Arrangement.Top else Arrangement.Bottom, horizontalAlignment: Alignment.Horizontal = Alignment.Start, flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), userScrollEnabled: Boolean = true, content: LazyListScope.() -> Unit ): Unit
modifier
: применяемые к контейнеру модификаторы
state
: объект состояния LazyListState, применяемый для управления состоянием контейнера
contentPadding
: отступы вокруг содержимого
reverseLayout
: при значении true
располагает элементы в обратном порядке
verticalArrangement
: настройки расположения элементов по вертикали
horizontalAlignment
: выравнивание элементов по горизонтали
flingBehavior
: описывает поведение при таком типе прокрутки, когда пользователь быстро перетаскивает что-то и поднимает палец.
Представляет объект FlingBehavior
userScrollEnabled
: указывает, доступна ли прокрутка жестами либо через специальные инструменты управления доступом
content
: устанавливает содержимое контейнера с помощью функции типа LazyListScope.() -> Unit
.
Одно из отличий lazy-контейнеров, в частности, LazyColumn от других контейнеров, например, от Column
состоит в принципе установки содержимого.
За это отвечает функция типа LazyListScope.() -> Unit
. Внутри блока этой функции можно использовать специальные методы для добавления других компонентов:
LazyListScope.item()
: для добавления одного элемента
LazyListScope.items()
: для добавления нескольких элементов
LazyListScope.itemsIndexed()
: для добавления нескольких элементов с использованием индексов
Например, применение функции LazyListScope.item()
для добавление в LazyColumn одного элемента:
LazyColumn( Modifier.fillMaxSize()){ item { Text("Hello METANIT.COM", fontSize = 28.sp) } }
В данном случае добавляется компонент Text.
Функция LazyListScope.items()
принимает список значений для каждого из которых создается элемент в LazyColumn:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val langs = listOf("Kotlin", "Java", "JavaScript", "Python", "C#", "C++", "Rust") LazyColumn( Modifier.fillMaxSize() ){ items(langs){lang -> Text(lang, fontSize = 24.sp)} } } } }
Здесь для создания содержимого в LazyColumn применяется список langs. Функция items
принимает этот список в качестве параметра и для каждого его элемента вызывает функцию
@Composable() (LazyItemScope.(item: T) -> Unit)
. Здесь в качестве такой функции выступает функция {lang -> Text(lang, fontSize = 24.sp)}
, которая для каждого элемента списка создает компонент Text
Причем для создания элементов можно сочетать сразу несколько функций item()/items()
:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val langs = listOf("Kotlin", "Java", "JavaScript", "Python", "C#", "C++", "Rust") LazyColumn( Modifier.fillMaxSize() ){ item { Text("Языки программирования", fontSize = 29.sp) } items(langs){lang -> Text(lang, fontSize = 24.sp)} } } } }
Еще одна функция itemsIndexed() аналогично items()
принимает список/массив элементов, но при переборе позволяет получить их индекс. Например,
применим индекс для определения фонового цвета компонента:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val langs = listOf("Kotlin", "Java", "JavaScript", "Python", "C#", "C++", "Rust") LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(5.dp) ){ item { Text("Языки программирования", fontSize = 29.sp) } itemsIndexed(langs){index,lang -> Text(lang, fontSize = 23.sp, modifier=Modifier.background( if(index%2==0) Color(0xffdddddd) else Color.Transparent ).padding(8.dp).fillMaxWidth())} } } } }
Контейнер LazyRow создает список с горизонтальной прокруткой. Он имеет следующие параметры:
@Composable fun LazyRow( modifier: Modifier = Modifier, state: LazyListState = rememberLazyListState(), contentPadding: PaddingValues = PaddingValues(0.dp), reverseLayout: Boolean = false, horizontalArrangement: Arrangement.Horizontal = if (!reverseLayout) Arrangement.Start else Arrangement.End, verticalAlignment: Alignment.Vertical = Alignment.Top, flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), userScrollEnabled: Boolean = true, content: LazyListScope.() -> Unit ): Unit
modifier
: применяемые к контейнеру модификаторы
state
: объект состояния LazyListState, применяемый для управления состоянием контейнера
contentPadding
: отступы вокруг содержимого
reverseLayout
: при значении true
располагает элементы в обратном порядке
horizontalArrangement
: настройки расположения элементов по горизонтали
verticalAlignment
: выравнивание элементов по вертикали
flingBehavior
: описывает поведение при таком типе прокрутки, когда пользователь быстро перетаскивает что-то и поднимает палец.
Представляет объект FlingBehavior
userScrollEnabled
: указывает, доступна ли прокрутка жестами либо через специальные инструменты управления доступом
content
: устанавливает содержимое контейнера с помощью функции типа LazyListScope.() -> Unit
.
В целом LazyRow похож на LazyColumn, таким же образом устанавливает элементы, только располагает их по горизонтали. Например, простейший горизонтальный список:
val langs = listOf("Kotlin", "Java", "JavaScript", "Python") LazyRow { items(langs) {lang -> Text(lang)} }
Также это может быть более сложное содержимое:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val langs = listOf(Language("Kotlin", 0xff16a085), Language("Java", 0xff2980b9), Language("JavaScript", 0xffd35400), Language("Python", 0xff2c3e50)) LazyRow{ items(langs) {lang -> Column(Modifier.padding(8.dp), horizontalAlignment = Alignment.CenterHorizontally){ Box(Modifier.size(100.dp).background(Color(lang.hexColor))) Text(lang.name, fontSize = 24.sp,modifier= Modifier.padding(8.dp)) } } } } } } data class Language(val name:String, val hexColor: Long)