LazyColumn — bu nədir, Compose-da effektiv siyahılar

Müəllif: IT Sectr Dərc olunub: 2026-02-24 Oxuma vaxtı: 10 dəq

LazyColumn — Jetpack Compose-un gecikməli yükləmə ilə sürüşdürülə bilən siyahıları göstərmək üçün komponenti. RecyclerView-dən fərqli olaraq, LazyColumn ViewHolder yaratmır və XML istifadə etmir — bütün elementlər composable-funksiyalar vasitəsilə deklarativ şəkildə təsvir olunur. LazyColumn-un nə olduğunu, LazyListState və items API-nin necə işlədiyini və 60 FPS səviyyəsində performansa necə nail olmağı göstəririk. IT Sectr-də LazyColumn-dan bütün yeni Compose layihələrində istifadə edirik. Klassik yanaşma ilə müqayisə üçün RecyclerView haqqında məqaləni oxuyun.

Əsas məqamlar

  • LazyColumn — Material Design 3-ün bir hissəsi olan, gecikməli yükləmə ilə şaquli siyahılar üçün Jetpack Compose komponenti.
  • LazyListState — siyahı vəziyyəti: sürüşdürmə mövqeyi, görünən elementlər, proqram sürüşdürməsi.
  • items API — məlumatları bağlamaq üçün açarları olan items(), itemsIndexed(), items() funksiyaları.
  • key — elementlərin sabit identifikasiyası üçün parametr, Compose-a kompozisiyanı təkrar istifadə etməyə imkan verir.
  • LazyVerticalGrid — sabit sayda sütunları olan şəbəkələr üçün LazyColumn versiyası.

Jetpack Compose-da LazyColumn nədir?

LazyColumn — Foundation Compose kitabxanasından olan, gecikməli (lazy) yükləmə ilə şaquli element siyahısını göstərən composable-funksiyadır: yalnız ekranda görünən və ya yaxınlıqda olan (prefetch zonası) elementlər yaradılır və kompozisiya olunur. LazyColumn Compose 1.0 (2021) ilə birlikdə LazyRow (üfüqi siyahı) və LazyVerticalGrid (şəbəkə) ilə birlikdə ortaya çıxdı.

Gecikməli yükləmə SubcomposeLayout mexanizmi vasitəsilə işləyir: LazyColumn mövcud yeri ölçür, LayoutInfo-dan görünən diapazonu tələb edir və yalnız bu diapazondakı elementləri kompozisiya edir. Ekrandan çıxan elementlər kompozisiyanı tərk edir (prefetch buferi istisna olmaqla). Google məlumatlarına görə (Android Performance, 2026), LazyColumn orta seqment cihazlarında 10000+ elementdən ibarət siyahını sürüşdürərkən 60 FPS təmin edir.

Column + ScrollState ilə fərq

Column şaquli sürüşdürmə ilə — verticalScroll modifierinin tətbiqi ilə bütün elementlərin bir-birinin altında adi yerləşdirilməsidir. Column gecikməli deyil: bütün uşaq elementlər görünməsələr belə dərhal kompozisiya olunur. 200+ elementdən ibarət siyahı üçün Column başlanğıcda əhəmiyyətli ləngiməyə səbəb olur. LazyColumn yalnız görünənləri + buferi (standart olaraq 1 ekran irəli/geri) kompozisiya edir, bu da onu uzun siyahılar üçün əvəzolunmaz edir.

items API: məlumatların siyahıya bağlanması

items API — LazyColumn üçün genişləndirmə funksiyaları dəsti, məlumat siyahısını və hər bir element üçün DSL təsvirini qəbul edir. Əsas funksiyalar: sabit say üçün items(count, key, itemContent), siyahı üçün items(list, key, itemContent), indekslə itemsIndexed(list, key, itemContent). key parametri — performans üçün məcburi şərt — Compose-a elementin sabit identifikatorunu verir.

kotlin
// itemContent ilə əsas LazyColumn
@Composable
fun ArticleList(articles: List<Article>) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        // Header — gecikməli deyil, həmişə başlanğıcda
        item {
            Text("Son məqalələr", style = MaterialTheme.typography.headlineMedium)
        }

        // Məqalələr siyahısı id ilə açar
        items(articles, key = { it.id }) { article ->
            ArticleCard(
                title = article.title,
                summary = article.summary,
                onClick = { onArticleClick(article.id) }
            )
        }

        // Yükləmə göstəricisi olan Footer
        item {
            CircularProgressIndicator(
                modifier = Modifier.fillMaxWidth().padding(16.dp)
            )
        }
    }
}

// Fərdi siyahı elementi
@Composable
fun ArticleCard(title: String, summary: String, onClick: () -> Unit) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = onClick)
    ) {
        Column(modifier = Modifier.padding(12.dp)) {
            Text(text = title, style = MaterialTheme.typography.titleMedium)
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = summary, style = MaterialTheme.typography.bodyMedium)
        }
    }
}

item {} vs items(): siyahıda həmişə mövcud olan tək elementlər (header, footer, ayırıcılar) üçün item {} istifadə edin. Dinamik məlumat siyahısı üçün items() istifadə edin. items() Iterable və ya Int və hər bir element üçün çağırılan DSL bloku qəbul edir. Bir LazyColumn-da item və items-i birləşdirin: çağırış sırası göstərilmə sırasını müəyyən edir.

LazyListState: sürüşdürmə mövqeyinin idarə edilməsi

LazyListState — siyahı vəziyyətini saxlayan obyekt: cari sürüşdürmə mövqeyi (firstVisibleItemIndex, firstVisibleItemScrollOffset), görünən elementlər (layoutInfo) və proqram sürüşdürmə metodları (scrollToItem, animateScrollToItem). LazyListState rememberLazyListState() vasitəsilə yaradılır və state parametri ilə LazyColumn-a ötürülür.

kotlin
// Sürüşdürmə mövqeyini qoruyan LazyColumn
@Composable
fun ScrollingList(items: List<Item>) {
    val listState = rememberLazyListState()

    Box(modifier = Modifier.fillMaxSize()) {
        LazyColumn(state = listState) {
            items(items, key = { it.id }) { item ->
                ListItemView(item = item)
            }
        }

        // "Yuxarı" düyməsi 10-cu elementdən sonra görünür
        val showButton by remember {
            derivedStateOf { listState.firstVisibleItemIndex > 10 }
        }

        AnimatedVisibility(visible = showButton) {
            FloatingActionButton(
                modifier = Modifier
                    .align(Alignment.BottomEnd)
                    .padding(16.dp),
                onClick = {
                    coroutineScope.launch {
                        listState.animateScrollToItem(0)
                    }
                }
            ) {
                Icon(Icons.Default.KeyboardArrowUp, "Yuxarı qalx")
            }
        }
    }
}

// Görünən elementlər haqqında məlumat almaq
@Composable
fun ListDebugInfo(listState: LazyListState) {
    val visibleItems = listState.layoutInfo.visibleItemsInfo
    val totalItems = listState.layoutInfo.totalItemsCount
    val firstItem = visibleItems.firstOrNull()?.index
    val lastItem = visibleItems.lastOrNull()?.index

    Text("$firstItem–$lastItem cəmi $totalItems-dən göstərilir")
}

Proqram sürüşdürməsi listState-in suspend-funksiyaları vasitəsilə yerinə yetirilir: scrollToItem(index, scrollOffset) — ani hərəkət (animasiyasız), animateScrollToItem(index) — animasiya ilə. Korutindən sürüşdürmək üçün LaunchedEffect və ya coroutineScope.launch istifadə edin. Vacib: kompozisiyadan (içəridə @Composable) suspend-funksiyaları çağırmayın — lambdalardan (onClick, LaunchedEffect) istifadə edin.

LazyColumn vs RecyclerView: yanaşmaların müqayisəsi

LazyColumnRecyclerView eyni vəzifəni həll edir — uzun siyahıların effektiv göstərilməsi. Fərq arxitekturadadır: RecyclerView ViewHolder və Adapter (klassik Android View) istifadə edir, LazyColumn — XML və ViewHolder olmadan deklarativ composable-funksiyalar. Seçim layihənin texnologiya stackindən asılıdır: Compose vs View-based UI.

ParametrLazyColumn (Compose)RecyclerView (View)
LayoutComposable-funksiyalar (Kotlin DSL)XML faylları + ViewBinding
Adapteritems() / itemsIndexed() DSLRecyclerView.Adapter + ViewHolder
Çeşidləmə/filtrasiyaSnapshot state + derivedStateOfDiffUtil + AsyncListDiffer
AnimasiyaAnimatedVisibility + Modifier.animateItemDefaultItemAnimator
Müxtəlif element tipləriitem {}/items() + tipə görə whengetItemViewType + çoxsaylı ViewHolder-lər
Mövqeyə sürüşdürməlistState.animateScrollToItem()layoutManager.scrollToPosition()
PrefetchIn-process (SubcomposeLayout buferi)RecycledViewPool + GapWorker
Şəbəkə/paginasıyacollectAsLazyPagingItems() + Paging 3PagingDataAdapter + Paging 3

Google tövsiyəsi (Android Developers, 2026): Jetpack Compose-da yeni layihələr üçün LazyColumn istifadə edin. View-based layihələr üçün RecyclerView istifadə edin. LazyColumn Compose tələb edir, bu da APK-ya təxminən 3–5 MB əlavə edir — köhnə cihazları dəstəkləyərkən bunu nəzərə alın. Əgər layihə artıq View sistemindən istifadə edirsə, LazyColumn AndroidView olmadan XML layoutu ilə eyni ekranda mövcud ola bilməz — belə hallarda RecyclerView-də qalmaq daha asandır.

LazyVerticalGrid və LazyHorizontalGrid: şəbəkələr

LazyVerticalGrid — sabit sayda sütunları (columns) olan şəbəkələr üçün LazyColumn versiyası. LazyHorizontalGrid — sabit sayda sətirləri (rows) olan üfüqi şəbəkə. Hər iki komponent LazyColumn ilə eyni gecikməli yükləmə prinsiplərindən və eyni items API-dən istifadə edir. columns parametri GridCells.Fixed(N) və ya GridCells.Adaptive(minSize) vasitəsilə sütunların sayını təyin edir.

kotlin
// Adaptiv sütunlarla şəbəkə
@Composable
fun PhotoGrid(photos: List<Photo>) {
    LazyVerticalGrid(
        columns = GridCells.Adaptive(minSize = 128.dp),
        contentPadding = PaddingValues(8.dp),
        horizontalArrangement = Arrangement.spacedBy(8.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(photos, key = { it.id }) { photo ->
            AsyncImage(
                model = photo.url,
                contentDescription = photo.title,
                modifier = Modifier.aspectRatio(1f)
            )
        }
    }
}

// Üfüqi siyahı (LazyRow)
@Composable
fun CategoryCarousel(categories: List<Category>) {
    LazyRow(
        contentPadding = PaddingValues(horizontal = 16.dp),
        horizontalArrangement = Arrangement.spacedBy(12.dp)
    ) {
        items(categories, key = { it.id }) { category ->
            FilterChip(
                selected = category.isSelected,
                onClick = { onCategoryClick(category.id) },
                label = { Text(category.name) }
            )
        }
    }
}

GridCells.Adaptive hüceyrənin minimum ölçüsünə əsasən sütunların sayını avtomatik hesablayır. Məsələn, GridCells.Adaptive(128.dp) 360 dp enində ekranda 2 sütun, 600 dp planşetdə 4 sütun yerləşdirir. GridCells.Fixed(2) həmişə düz 2 sütun göstərir. Adaptive çoxekranlı adaptasiya üçün daha üstündür — media sorğuları olmadan ekran eninə avtomatik uyğunlaşır.

LazyColumn performansı: key, contentType, prefetch

Performans LazyColumn üç amildən asılıdır: açarların sabitliyi (key), məzmun növü (contentType) və prefetch buferi (beyondBounds). Standart olaraq LazyColumn 1 ekran irəli və 1 geri buferləyir. Google (Android Developers, 2026) bu parametrləri müxtəlif element tipləri və ya mürəkkəb kompozisiyası olan siyahılar üçün konfiqurasiya etməyi tövsiyə edir.

ParametrTəsvirTövsiyə
keyElementin sabit identifikatoruHəmişə key = { it.id } təyin edin. Key olmadan Compose indeksdən istifadə edir və elementlərin dəyişdirilməsi animasiyanı pozur.
contentTypeHovuzların bölünməsi üçün məzmun növüMüxtəlif element tipləri olan siyahılar üçün təyin edin (mətn + şəkil + reklam). Compose yalnız bir contentType daxilində kompozisiyanı təkrar istifadə edəcək.
beyondBoundsPrefetch üçün ekranların sayıAğır şəkilləri olan siyahılar üçün 2–3-ə qədər artırın. Standart olaraq 1 ekran.
Modifier.animateItemMövqe dəyişmə animasiyasıAnimasiyalı çeşidləmə və filtrasiya üçün istifadə edin (Compose 1.7+).
kotlin
// contentType və prefetch ilə optimallaşdırılmış LazyColumn
@Composable
fun OptimizedFeed(items: List<FeedItem>) {
    val listState = rememberLazyListState()

    LazyColumn(
        state = listState,
        modifier = Modifier.fillMaxSize(),
        beyondBoundsPageCount = 2  // prefetch 2 ekran
    ) {
        items(
            items = items,
            key = { it.id },
            contentType = { it.type }  // növlərə görə bölmə
        ) { item ->
            when (item) {
                is FeedItem.Post -> PostView(item)
                is FeedItem.Ad -> AdView(item)
                is FeedItem.Suggested -> SuggestedView(item)
            }
        }
    }
}

// listState vasitəsilə performansın ölçülməsi
@Composable
fun ScrollPerformance(listState: LazyListState) {
    val scrollInfo = listState.layoutInfo
    val visibleCount = scrollInfo.visibleItemsInfo.size
    val total = scrollInfo.totalItemsCount

    // derivedStateOf — dəyər dəyişməyibsə yenidən tərtib etmir
    val scrollProgress by remember {
        derivedStateOf {
            if (total > 0) visibleCount.toFloat() / total else 0f
        }
    }

    LinearProgressIndicator(
        progress = scrollProgress,
        modifier = Modifier.fillMaxWidth().height(2.dp)
    )
}

Ümumi səhvlər: (1) key-in olmaması — elementlər siyahının hər dəyişməsində yenidən kompozisiya olunur; (2) snapshot axınları olmadan mutableStateListOf istifadəsi — dəyişikliklər izlənilməyə bilər; (3) itemContent daxilində suspend-funksiyaların çağırılması — kompozisiyanı kəsir; (4) qarışıq tiplər üçün contentType olmaması — Compose mətn postu üçün reklam kompozisiyasını təkrar istifadə edir, vizual artefaktlara səbəb olur. IT Sectr-də üç və daha çox məzmun növü olan bütün siyahılara contentType əlavə edirik.

Tez-tez verilən suallar

LazyColumn yavaş sürüşür — nə etməli?

Üç parametri yoxlayın: (1) key — sabit açar olmadan Compose kompozisiyanı təkrar istifadə edə bilməz, (2) contentType — müxtəlif element tipləri olan siyahılar üçün, (3) beyondBoundsPageCount — şəkillər üçün 2-yə qədər artırın. itemContent daxilində ağır hesablamaları məlumat açarı ilə remember-ə köçürün. Sadə qrafika üçün Image əvəzinə Modifier.drawWithContent istifadə edin.

LazyColumn elementləri arasında ayırıcı necə əlavə etməli?

Elementlər arasında boşluqlar üçün LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) istifadə edin. Xətt ilə vizual ayırıcı üçün items arasında item { Divider() } əlavə edin. Avtomatik ayırıcı: items(items, key = { it.id }) { item -> ... }, hər bir element arasında item { HorizontalDivider() } daxil edin. Bunun üçün LazyListScope.items(list, key) { /* element */ } və ayrıca LazyListScope.item { Divider() } istifadə edin.

LazyColumn Column içərisində işləmir — niyə?

LazyColumn standart olaraq sonsuz hündürlüyə malikdir (fillMaxSize). Sabit hündürlüyü olmayan Column içərisində LazyColumn ölçüsünü təyin edə bilməz. Həll yolu: (1) LazyColumn-a sabit hündürlük təyin edin: Modifier.height(400.dp), (2) Column daxilində Modifier.weight(1f) istifadə edin, (3) LazyColumn-u şaquli sürüşdürülən konteynerə yerləşdirməyin — LazyColumn-u header və footer üçün item {} ilə kök element kimi istifadə edin.

Məlumat dəyişdikdə LazyColumn-u necə yeniləməli?

LazyColumn State dəyişikliklərinə avtomatik reaksiya verir. Məlumat mutableStateListOf və ya mutableStateOf-də saxlanılırsa, Compose yalnız dəyişmiş elementləri yenidən kompozisiya edir. ViewModel-dən siyahılar üçün Flow ilə collectAsState() istifadə edin. Key ilə siyahı yenilənərkən Compose Modifier.animateItemPlacement() vasitəsilə dəyişiklikləri (əlavə etmə, silmə, daşıma) avtomatik animasiya edir.

LazyColumn vs LazyVerticalGrid — nə seçməli?

LazyColumn — bir sütunlu siyahılar üçün (lent, söhbət, şərhlər). LazyVerticalGrid — şəbəkələr üçün (qalereya, kataloq, ikonlar). Elementlər telefonda bir sütunda, planşetdə isə iki sütunda olmalıdırsa — GridCells.Adaptive ilə LazyVerticalGrid istifadə edin. Qarışıq şəbəkə (bir bölmədə müxtəlif sayda sütunlar) lazımdırsa — LazyColumn istifadə edin və items daxilində üfüqi LazyRow və ya iç-içə LazyVerticalGrid yerləşdirin.

Nəticə

  • LazyColumn — deklarativ API ilə gecikməli şaquli siyahılar üçün Jetpack Compose komponenti.
  • items() API siyahı və hər bir element üçün DSL bloku qəbul edir; key performans üçün məcburidir.
  • LazyListState sürüşdürmə mövqeyini idarə edir, proqram sürüşdürməsi üçün suspend-funksiyalar təqdim edir.
  • contentType müxtəlif element tipləri olan siyahılar üçün kompozisiya hovuzlarını ayırır.
  • LazyVerticalGrid / LazyRow — eyni items API ilə şəbəkələr və üfüqi siyahılar üçün variantlar.
  • LazyColumn SubcomposeLayout və prefetch buferi sayəsində 10000+ element üçün 60 FPS təmin edir.
  • Yeni Compose layihələri üçün LazyColumn istifadə edin; View-based layihələr üçün — RecyclerView.

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun