---
title: 'Tembel Listeler'
source: 'https://academia.sh/tr/kurslar/compose/tembel-listeler'
course: 'Jetpack Compose ile Arayüz'
language: tr
updated: '2026-10-21T05:02:38+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Tembel listenin yalnız görünen aralıktaki satırları ağaca aldığını ölçer'
    - 'Kaydırma konumunun listeden durumun sahibine yukarı gittiğini gösterir'
    - 'Ekranda olmayan satıra giden verinin ağaç dışında kaldığını ayırt eder'
    - 'Öge anahtarının satırın kimliğini konumdan ayırdığını açıklar'
---

# Tembel Listeler

Tembel listede yalnız görünen satırların arayüz ağacına girmesinin, kaydırma konumunun sahibine çıkışının ve ağaçta olmayan satıra giden verinin ölçümü.

Önceki derste ögelerin hepsi ağaçtaydı ve bir öge ötekine ancak ebeveyn üzerinden bağlanabiliyordu. Bir satır listesinde bu varsayım pahalıya gelir: bin satırlık bir sepeti bin düğümle kurmak, ekranda beş satır görünürken de bin satırı ölçmek ve yerleştirmek demektir. Tembel liste bunu yapmaz. Yalnız görünen aralıktaki satırlar için düğüm oluşturur; kullanıcı kaydırdıkça aralık kayar, ekrandan çıkan satırın düğümü ağaçtan düşer ve yeni giren satır için yenisi kurulur.

Bu durum ağaç ölçüsünü doğrudan etkiler. Ağaçta olmayan bir düğüme veri gönderilemez. Bu ders, bir satırın ağaçta bulunup bulunmamasının, ona giden verinin yönünü nasıl değiştirdiğini ölçer. Aynı derste ters yöndeki bir veri de ölçülür: listenin kaydırma konumu, listeyi kullanan ekrana nasıl ulaşır?

```kotlin
// Direction.kt — bir verinin arayuz agacinda hangi yone gittigini siniflandirir
class Tree(private val parentOf: Map<String, String>) {
    fun contains(node: String): Boolean = node in parentOf.keys || node in parentOf.values
    fun parent(node: String): String? = parentOf[node]
    fun ancestors(node: String): List<String> {
        val chain = mutableListOf<String>()
        var current = parentOf[node]
        while (current != null) {
            chain.add(current)
            current = parentOf[current]
        }
        return chain
    }
}

class Move(val label: String, val from: String, val to: String, tree: Tree) {
    val direction: String = when {
        !tree.contains(from) || !tree.contains(to) -> "dis"
        to in tree.ancestors(from) -> "yukari"
        tree.parent(to) == from -> "asagi"
        from in tree.ancestors(to) -> "derin"
        else -> error("akrabasiz: $from ve $to")
    }

    fun describe() {
        println("$label: kimden=$from | kime=$to -> $direction")
    }
}

fun countDirections(moves: List<Move>) {
    for (name in listOf("asagi", "yukari", "derin", "dis")) {
        println("$name: ${moves.count { it.direction == name }}")
    }
}
```

## Tembel Liste ve Öge

`LazyColumn`, dikey tembel listedir; yatay karşılığı `LazyRow`'dur. Satırlar `items` ile tanımlanır: bir koleksiyon ve her öge için bir bileşen işlevi verilir. Sütun ve satır düzenleri çocuklarını bir kerede ölçerken tembel liste, ölçmeyi görünen aralıkla sınırlar. Kaydırma konumu bir durum nesnesinde tutulur (`LazyListState`); bu nesneyi oluşturan ve hatırlayan bileşen işlevi, konumu okuyabilir.

```kotlin
// Platform kodu: tembel liste, ogeler ve kaydirma durumu
@Composable
fun CartList(products: List<Product>) {
    val listState = rememberLazyListState()
    LazyColumn(state = listState) {
        items(products, key = { it.id }) { product ->
            ProductRow(product)
        }
    }
    val first = listState.firstVisibleItemIndex
}
```

Burada `CartList`, `listState`'in sahibidir: durumu o oluşturur ve hatırlar. `LazyColumn` bu durumu parametre olarak alır, kaydırma değiştikçe onu günceller. Satırlar `items` lambdasında oluşturulur, bu yüzden ağaçta `LazyColumn`'un çocuklarıdır. `CartList`, `LazyColumn`'un ebeveynidir.

Model, platformun bu kuralını kurar. Model, platformun kendisi değildir. Yardımcı dosya iki şey yapar: toplam satır sayısı, ilk görünen satırın sırası ve ekrana sığan satır sayısından görünen aralığı çıkarır; sonra bu aralıktaki satırlardan bir arayüz ağacı kurar. Ağaç `Screen`'in altında `LazyList`'i, onun altında yalnız görünen satırları taşır. Ölçümlerin uçlarını da iki işlev verir: `rowName` bir satırın düğüm adını üretir, `scrollOwner` listenin ebeveynini ağaçtan okur. Bu derste hareketin uçları elle yazılmaz; en az bir ucu bu işlevlerden gelir.

```kotlin
// Window.kt — tembel listenin gorunen satirlari (modelin hesabi)
fun visibleRows(total: Int, firstVisible: Int, viewportRows: Int): List<String> =
    (firstVisible until minOf(total, firstVisible + viewportRows)).map { rowName(it) }

fun rowName(index: Int): String = "Row$index"

fun scrollOwner(tree: Tree): String = tree.parent("LazyList") ?: error("liste kokte")

fun listTree(rows: List<String>): Tree {
    val parentOf = mutableMapOf("Screen" to "App", "LazyList" to "Screen")
    for (row in rows) {
        parentOf[row] = "LazyList"
    }
    return Tree(parentOf)
}
```

## Görünen Aralık

İlk ölçüm bin satırlık bir koleksiyonu ele alır. Ekrana beş satır sığar ve liste en başta durur. Ağaçta kaç satır olduğu, ve ilk görünen satıra giden verinin yönü basılır.

```kotlin
// Main.kt — bin satirlik listede agactaki satirlar
fun main() {
    val rows = visibleRows(1000, 0, 5)
    val tree = listTree(rows)
    println("agactaki satir: ${rows.size}")
    println("satirlar: ${rows.joinToString(",")}")
    val moves = listOf(Move("veri-ilk-satir", "LazyList", rows.first(), tree))
    for (move in moves) {
        move.describe()
    }
}
```

```text
agactaki satir: 5
satirlar: Row0,Row1,Row2,Row3,Row4
veri-ilk-satir: kimden=LazyList | kime=Row0 -> asagi
```

Bin satırdan beşi ağaçtadır. Listenin ilk satıra verdiği veri, ebeveynden çocuğa, yani aşağı gitti. Bu, önceki derslerdeki sütun çocuğuyla aynı hareketin tembel bir listedeki biçimidir.

**AD1.** Model ekrana sığan satır sayısını sabit alır ve satır yüksekliklerini hesaba katmaz. Platformun görünür aralığın hemen ötesindeki satırları önceden hazırlayabileceği de modelde yoktur.

## Kaydırma Konumu Sahibine Çıkar

Kullanıcı kaydırınca ilk görünen satır değişir. Bu bilgiyi liste üretir: kaydırma jestini işleyen liste, durum nesnesine yeni konumu yazar. Durumun sahibi `Screen` ya da onun altındaki bir bileşen işleviyse, konum listeden sahibine gitmiş olur. Liste, sahibinin altındadır, yani sahibi listenin atasıdır; hareket çocuktan ataya gider: yukarı.

Aşağıdaki ölçüm listeyi üç satır kaydırır. Aralık `Row3`'ten `Row7`'ye kayar; `Row0` ağaçtan çıkar, `Row5`...`Row7` ise öncekinde olmayan yeni satırlardır. Kaydırma konumu `Screen`'e gider.

```kotlin
// Main.kt — kaydirma sonrasi aralik ve konumun sahibine cikisi
fun main() {
    val before = visibleRows(1000, 0, 5)
    val after = visibleRows(1000, 3, 5)
    val tree = listTree(after)
    println("once: ${before.joinToString(",")}")
    println("sonra: ${after.joinToString(",")}")
    println("ilk gorunen sira: 3")
    val moves = listOf(Move("kaydirma-konumu", "LazyList", scrollOwner(tree), tree))
    for (move in moves) {
        move.describe()
    }
}
```

```text
once: Row0,Row1,Row2,Row3,Row4
sonra: Row3,Row4,Row5,Row6,Row7
ilk gorunen sira: 3
kaydirma-konumu: kimden=LazyList | kime=Screen -> yukari
```

Aralık beş satırlık kaldı, ama içerik değişti: `Row0`, `Row1` ve `Row2` ağaçtan çıktı; `Row5`, `Row6` ve `Row7` girdi. Kaydırma konumu `LazyList`'ten `Screen`'e yukarı gitti. Bu hareket kullanıcının parmağından değil, listenin kendi durumundan gelir; ekran bu sayede "kullanıcı beşinci satıra yaklaştı" gibi bir bilgiyi okuyabilir.

**AD2.** Model kaydırma konumunu tek bir tamsayı, ilk görünen satırın sırası olarak taşır. Platformun satır içindeki kaydırma kaymasını da ayrıca tuttuğu bu derste ölçülmedi.

## Anahtar Kimliktir

Ağaçtan düşen ve yeniden giren bir satırın durumu, hangi satır olduğuna göre korunmalıdır. `items` çağrısına verilen `key`, satırın kimliğini belirler. Anahtar verilmezse platform kimliği satırın konumundan türetir; listenin başına yeni bir ögenin eklenmesi her satırın konumunu bir kaydırır ve konuma bağlı durumlar yanlış satıra geçer. Anahtar verilirse durum ögeyle birlikte hareket eder. Anahtar, listede benzersiz olmalıdır.

Bu bölüm bir ölçüm içermez. Kimliğin konumdan ayrılması bir yön sorusu değil, bir eşleştirme sorusudur: aynı veri bir satırdan ötekine mi geçti, yoksa aynı satırda mı kaldı? Böyle bir eşleştirme, ağaç ilişkisini değil, düğümün kimliğini ilgilendirir. Bu dersin ekseni olan yön, anahtar değişse de değişmez: satıra veri hâlâ listeden gider.

## Ağaçta Olmayan Satır

Kaydırmadan sonra `Row0` ağaçta değildir. Listenin elinde `Row0`'a ait veri hâlâ vardır, çünkü koleksiyon listenin dışında tutulur. Ancak o veriyi alacak düğüm yoktur. Çekirdek, uçlardan birinin ağaçta bulunmadığı her hareketi dış olarak sınıflar.

```kotlin
// Main.kt — gorunen ve gorunmeyen satira ayni veri
fun main() {
    val tree = listTree(visibleRows(1000, 3, 5))
    val moves = listOf(
        Move("veri-satir-3", "LazyList", rowName(3), tree),
        Move("veri-satir-7", "LazyList", rowName(7), tree),
        Move("veri-satir-0", "LazyList", rowName(0), tree),
    )
    for (move in moves) {
        move.describe()
    }
    countDirections(moves)
}
```

```text
veri-satir-3: kimden=LazyList | kime=Row3 -> asagi
veri-satir-7: kimden=LazyList | kime=Row7 -> asagi
veri-satir-0: kimden=LazyList | kime=Row0 -> dis
asagi: 2
yukari: 0
derin: 0
dis: 1
```

Aynı kaynaktan çıkan aynı biçimdeki veri, görünen iki satıra aşağı gitti; ağaçta olmayan satıra dış gitti. Yönü değiştiren şey verinin içeriği ya da kaynağı değil, hedefin ağaçta bulunup bulunmamasıdır. Bu yüzden ekranda olmayan bir satırın durumunu okumak ya da ona doğrudan bir değişiklik yazmak mümkün değildir. O satırla ilgili her şey, satır ağaca yeniden girdiğinde, listenin elindeki koleksiyondan yeniden verilir.

**AD3.** Model ağaçtan düşen satırın durumunun ne olduğunu kurmaz. Satırın kendi hatırladığı değerlerin ağaçtan düşünce kaybolup kaybolmadığı ve kaydedilebilir durumun bunu nasıl değiştirdiği bu derste ölçülmedi.

## Sınırlayıcı Ölçüm

Dersin yönünü, listenin iki ucundaki verilerden hangisinin ders konusuna özgü olduğu belirler. Bir öge verisinin görünen satıra gitmesi, önceki derslerdeki sütun çocuğuyla aynıdır: aşağı. Tembel listeye özgü olan iki şeydir: ağaçta olmayan satıra giden verinin dış kalması ve kaydırma konumunun sahibine çıkması. Aşağıdaki ölçüm bunları bir araya getirir.

```kotlin
// Main.kt — listenin dort hareketinin yon dokumu
fun main() {
    val rows = visibleRows(1000, 3, 5)
    val tree = listTree(rows)
    val moves = listOf(
        Move("veri-ilk-satir", "LazyList", rows.first(), tree),
        Move("veri-son-satir", "LazyList", rows.last(), tree),
        Move("veri-gorunmeyen", "LazyList", rowName(0), tree),
        Move("kaydirma-konumu", "LazyList", scrollOwner(tree), tree),
    )
    for (move in moves) {
        move.describe()
    }
    countDirections(moves)
}
```

```text
veri-ilk-satir: kimden=LazyList | kime=Row3 -> asagi
veri-son-satir: kimden=LazyList | kime=Row7 -> asagi
veri-gorunmeyen: kimden=LazyList | kime=Row0 -> dis
kaydirma-konumu: kimden=LazyList | kime=Screen -> yukari
asagi: 2
yukari: 1
derin: 0
dis: 1
```

İki aşağı, bir yukarı, bir dış. Aşağı giden iki hareket, ebeveynin çocuğuna verdiği olağan veridir. Dış hareket, listenin tembel olmasının bedelidir. Yukarı hareket ise tembel listenin ekran için taşıdığı bilgidir: konum. Satırlara veri vermek için liste zaten çalışır; ekranın listeyi izleyebilmesi içinse konumun yukarı çıkması gerekir. Dersin yönü: **yukarı**.

**AD4.** Model dört hareketi tek bir kaydırma konumunda kurar. Konum değiştikçe hareket sayıları da değişir; bu ölçüm yalnız `firstVisible` 3 iken geçerlidir.

## Özet

- Bu dersin yönü: yukarı. Tembel listeye özgü hareket, kaydırma konumunun listeden durumun sahibine çıkmasıdır.
- Tembel liste yalnız görünen aralıktaki satırlar için düğüm oluşturur; ağaçtaki satır sayısı toplam sayıdan küçüktür.
- Listenin görünen satıra verdiği veri aşağı gider.
- Kaydırma konumu listeden durumun sahibine, yani ataya gider: yukarı.
- Ağaçta olmayan satıra giden veri dıştır; satır ağaca girene kadar bekler.

## Sonraki Adım

Tembel liste, satırlarını kendisi oluşturur ama satırın içeriğini bileşen işlevi belirler. Hazır arayüz bileşenleri bu içeriği önceden kurulmuş parçalarla sağlar; ve bu parçalar içeriklerine kendi renklerini verir. Sonraki ders, düğmenin içeriğine verdiği rengin yönünü ölçer.
