İçeriğe geç
academia.sh

Ders 12 / 17

İskele Yapısı

Ekran iskelesinin içeriğine verdiği iç boşluğun ağaçta aşağı gitmesinin, iskelenin yuvasına yazılan ama ekranın durumunu okuyan içeriğin ise derin bir yoldan beslenmesinin ölçümü.

Yayın Güncelleme

Bu derste

  • İskelenin içeriğe verdiği iç boşluğun aşağı gittiğini ölçer
  • Yuva lambdasının yazıldığı yer ile ağaçtaki yerinin farklı olduğunu gösterir
  • Ekranın durumunun iskeleyi atlayarak yuvaya derin gittiğini ayırt eder
  • İç boşluğun neden iskeleden, durumun neden yazıldığı yerden geldiğini açıklar
İçindekiler

Bir ekranın üstünde başlık çubuğu, altında gezinme çubuğu, ortasında içerik bulunur. Bunları elle yerleştirmek mümkündür, ama çubukların yüksekliğini içeriğe bildirmek gerekir; aksi halde içeriğin ilk satırı başlık çubuğunun altında kalır. İskele bu işi üstlenir: üst çubuğu, alt çubuğu ve içeriği ayrı yuvalara alır, çubukların kapladığı yeri ölçer ve içeriğe iç boşluk olarak verir.

Bu ders iki veriyi karşılaştırır. Biri iskelenin içeriğe verdiği iç boşluktur ve kaynağı iskelenin kendisidir. Öteki ekranın durumudur, ve içeriğe iskeleden geçmeden ulaşır. İkisi aynı yuvaya varır, ama yönleri farklıdır.

// 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 }}")
    }
}

Yuvalar ve İç Boşluk

İskele, adlandırılmış yuvalar alır: topBar, bottomBar ve content. İçerik yuvası bir lambdadır ve bu lambda iskelenin hesapladığı iç boşluğu parametre olarak alır. Bu parametre PaddingValues türündedir ve dört kenarın boşluğunu taşır.

// Platform kodu: iskele ve icerigine verdigi ic bosluk
@Composable
fun CartScreen(cartCount: Int) {
    Scaffold(
        topBar = { CartTopBar(title = "Sepet ($cartCount)") },
    ) { innerPadding ->
        CartContent(Modifier.padding(innerPadding), cartCount)
    }
}

Yuva lambdasındaki innerPadding, iskelenin verdiği değerdir; içerik bunu kendi kenar boşluğu olarak kullanır. Kullanılmazsa içerik çubukların altına taşar. Aynı lambda cartCount’u da okur. Bu değer lambdanın yazıldığı işlevin, yani CartScreen’in parametresidir.

Model, platformun bu kuralını kurar; model platformun kendisi değildir. Yardımcı dosya, iskelenin yuvalarını ağaca yerleştirir ve çubuk yüksekliklerinden içerik için iç boşluğu hesaplar.

// Scaffold.kt — yuvalar ve ic bosluk (modelin hesabi)
class Insets(val top: Int, val bottom: Int)

fun scaffoldSlots(hasBottomBar: Boolean): List<String> =
    if (hasBottomBar) listOf("TopBar", "Content", "BottomBar") else listOf("TopBar", "Content")

fun scaffoldTree(slots: List<String>): Tree {
    val parentOf = mutableMapOf("Screen" to "App", "Scaffold" to "Screen")
    for (slot in slots) {
        parentOf[slot] = "Scaffold"
    }
    return Tree(parentOf)
}

fun contentInsets(topBar: Int, bottomBar: Int): Insets = Insets(topBar, bottomBar)

İç Boşluk İskeleden Gelir

İlk ölçümde üst çubuk 56, alt çubuk 80 birim yüksekliktedir. İskele bunlardan içerik için iç boşluğu hesaplar ve içerik yuvasına verir.

// Main.kt — iskelenin icerige verdigi ic bosluk
fun main() {
    val slots = scaffoldSlots(true)
    val tree = scaffoldTree(slots)
    val insets = contentInsets(56, 80)
    println("ic bosluk: ust=${insets.top} alt=${insets.bottom}")
    val move = Move("ic-bosluk", "Scaffold", slots[1], tree)
    move.describe()
}
ic bosluk: ust=56 alt=80
ic-bosluk: kimden=Scaffold | kime=Content -> asagi

İç boşluk 56 ve 80 olarak içeriğe ulaştı; hareket iskeleden doğrudan çocuğuna gitti: aşağı. İskele içeriği çocuğu olarak kurduğu için bu hareket her zaman bir kat iner. İçerik hangi çubuk düzenini kullanırsa kullansın, boşluk iskelenin hesabından gelir.

AD1. Model çubuk yüksekliklerini iki tamsayı olarak alır. Çubukların içeriğe göre uzaması, sistem çubuklarının kapladığı kenar boşlukları ve klavye boşluğu modelde yoktur.

Yuva Lambdasının İki Yeri

Yuva lambdası CartScreen içinde yazılmıştır, bu yüzden cartCount’u yakalayabilir. Ağaçta ise lambdanın ürettiği içerik iskelenin çocuğudur; CartScreen ile arasında iskele düğümü vardır. Bir öge kaynak kodda CartScreen’in içinde yazıldığı için ağaçta onun doğrudan çocuğu olmaz.

Bu fark yönü belirler. cartCount, CartScreen’den içeriğe gider. Hareket iskele düğümünün üstünden atlar: iskele bu değeri ne okur ne dönüştürür, yalnız yuvayı yerleştirir. Değer yakalama yoluyla ulaşır.

// Main.kt — ekranin durumu iskelenin ustunden gecer
fun main() {
    val slots = scaffoldSlots(true)
    val tree = scaffoldTree(slots)
    val moves = listOf(
        Move("sepet-sayisi", "Screen", slots[1], tree),
        Move("baslik", "Screen", slots.first(), tree),
    )
    for (move in moves) {
        move.describe()
    }
    countDirections(moves)
}
sepet-sayisi: kimden=Screen | kime=Content -> derin
baslik: kimden=Screen | kime=TopBar -> derin
asagi: 0
yukari: 0
derin: 2
dis: 0

İkisi de derin. Sepet sayısı içeriğe, başlık üst çubuğa iskeleyi atlayarak gitti. İskeleye hiçbir parametre verilmedi; değerler yuva lambdalarının içinde okundu. Bu durum iskeleyi sağlam kılar: iskele ekranın durumundan habersizdir ve yeni bir durum eklemek iskele çağrısını değiştirmez.

AD2. Model yakalama ile ağaç ilişkisini aynı çizgide gösterir. Platformun lambdayı hangi koşulda yeniden çalıştırdığı, yakalanan değerin değişince içeriğin nasıl güncellendiği modelde yok.

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

Dersin yönü iki hareketten birine bağlı değildir: ikisi de aynı yuvalara varır ve ikisi de gerçektir. Yön, iskeleye ait olan veriyle ekrana ait olan veriyi ayırmaktan çıkar. Aşağıdaki ölçüm dördünü birlikte gösterir: ekranın iskeleye verdiği yuvalar, iskelenin içeriğe verdiği iç boşluk, ve ekranın durumunun içeriğe ve üst çubuğa gidişi.

// Main.kt — iskele cevresindeki dort hareket
fun main() {
    val slots = scaffoldSlots(true)
    val tree = scaffoldTree(slots)
    val moves = listOf(
        Move("yuvalar", "Screen", "Scaffold", tree),
        Move("ic-bosluk", "Scaffold", slots[1], tree),
        Move("sepet-sayisi", "Screen", slots[1], tree),
        Move("baslik", "Screen", slots.first(), tree),
    )
    for (move in moves) {
        move.describe()
    }
    countDirections(moves)
}
yuvalar: kimden=Screen | kime=Scaffold -> asagi
ic-bosluk: kimden=Scaffold | kime=Content -> asagi
sepet-sayisi: kimden=Screen | kime=Content -> derin
baslik: kimden=Screen | kime=TopBar -> derin
asagi: 2
yukari: 0
derin: 2
dis: 0

yuvalar satırının iki ucu da elle yazılmıştır: bu satır kuralı göstermek için yazılmıştır, ölçüm değildir. Ölçüm sayılan ic-bosluk, sepet-sayisi ve baslik satırlarının bir ucu modelin yuvalarından gelir: aşağı 1, derin 2.

İki aşağı, iki derin. İskeleye giren ve iskeleden içeriğe çıkan her şey bir kat iner: iskelenin kendi sözleşmesi budur. Ekranın durumu ise bu sözleşmenin dışında, yakalama yoluyla iner ve iskeleyi atlar. İç boşluk yalnız iskelede bilinen çubuk yüksekliklerinden türer; durum ise yalnız yazıldığı yerde bilinir. Her veri, bilindiği yerden gelir. İskelenin sözleşmesindeki hareketin yönü: aşağı.

AD3. Model dört hareketi tek bir çubuk düzeninde kurar. Çubuksuz bir iskelede iç boşluk sıfır olurdu, ama bu dersin ölçümleri onu kapsamaz.

Özet

  • Bu dersin yönü: aşağı. İskelenin kendi sözleşmesindeki hareket, iç boşluğun iskeleden içeriğe inmesidir.
  • İskele üst çubuk, alt çubuk ve içerik yuvalarını yerleştirir ve çubukların kapladığı yeri içeriğe iç boşluk olarak verir.
  • İç boşluk iskeleden içeriğe, doğrudan çocuğa gider: aşağı.
  • Yuva lambdası ekranın içinde yazılır, ama ağaçta iskelenin çocuğudur.
  • Lambdanın yakaladığı ekran durumu iskeleyi atlar: derin.

Sonraki Adım

İskele içeriğini ekranın içinde yerleştirir; ama kullanıcı bir ekrandan ötekine geçtiğinde yerleştirilecek içerik değişir. Sonraki ders, ekranlar arası gezinmeyi, rotalarla hedefi seçmeyi ve henüz ağaçta olmayan bir hedefe argüman götürmeyi ölçer.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat