İçeriğe geç
academia.sh

Ders 14 / 17

Tema ve Tipografi

Kökte sağlanan temanın ağaçta derindeki metne kadar inmesinin, bir alt ağacın kendi temasını sağlayınca en yakın sağlayıcının değişmesinin ve yönün buna bağlı değişiminin ölçümü.

Yayın Güncelleme

Bu derste

  • Kökte sağlanan temanın derindeki metne derin yönde gittiğini ölçer
  • En yakın sağlayıcıyı ağaçtaki atalar arasından seçen bir model kurar
  • Alt ağacın kendi temasını sağlamasının hareketin yönünü değiştirdiğini gösterir
  • Tema değerinin neden parametre olarak taşınmadığını açıklar
İçindekiler

Bir uygulamanın renkleri, yazı tipi boyutları ve köşe yuvarlaklıkları tek bir yerde seçilir ve her ekranda kullanılır. Bu değerleri her bileşen işlevine parametre olarak vermek mümkündür, ama ağaç derinleştikçe parametre zinciri uzar ve aradaki her işlev, yalnız iletmek için bir parametre taşır. Tasarım sistemleri bunu başka türlü çözer: değer ağacın bir noktasında sağlanır, altındaki herkes onu okur.

Bu ders, o çözümün yönünü ölçer. Tema kökte sağlanır ve derindeki metne iner; aradaki hiçbir işlev onu taşımaz. Bir alt ağaç kendi temasını sağladığında ise okuyucu için en yakın sağlayıcı değişir, ve hareketin hangi düğümden çıktığı da değişir.

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

Tema Bir Sağlayıcıdan İner

Tema, bir sarmalayıcı işlevle sağlanır: bu işlev renk şemasını, tipografiyi ve şekilleri içeren değerleri altındaki içerik için kurar. Altındaki bir metin bu değerlere tema nesnesi üzerinden erişir. Erişimin altında oluşturma yereli adı verilen mekanizma vardır: bir yerel, ağacın bir düğümünde değer alır ve o düğümün altındaki her işlev onu okuyabilir.

// Platform kodu: tema saglayici ve metnin temayi okumasi
@Composable
fun AppScreen() {
    MaterialTheme(colorScheme = lightColorScheme()) {
        Header {
            Text(
                text = "Siparisler",
                color = MaterialTheme.colorScheme.primary,
                style = MaterialTheme.typography.titleLarge,
            )
        }
    }
}

Text, rengi ve yazı stilini AppScreen’den parametre olarak almaz; temadan okur. Araya giren Header temadan habersizdir ve onu iletmez. Yerel, değeri kendiliğinden altındakilere ulaştırır.

Model, platformun bu kuralını kurar; model platformun kendisi değildir. Yardımcı dosya iki şey yapar: bir ekranın ağacını kurar ve bir okuyucu için en yakın tema sağlayıcısını ataları arasından seçer.

// Theme.kt — agac ve en yakin saglayici (modelin hesabi)
fun themeTree(): Tree = Tree(
    mapOf(
        "Screen" to "App",
        "Header" to "Screen",
        "Title" to "Header",
        "Panel" to "Screen",
        "Label" to "Panel",
    )
)

fun closestTheme(tree: Tree, providers: List<String>, reader: String): String =
    tree.ancestors(reader).first { it in providers }

ancestors listesi okuyucudan köke doğru sıralıdır; ilk eşleşen sağlayıcı en yakın olandır.

Kökten Derine

İlk ölçümde yalnız ekran kökü tema sağlar. İki okuyucu vardır: başlık metni Header içinde, etiket Panel içinde. Her ikisi de temayı en yakın sağlayıcıdan, yani kökten alır.

// Main.kt — tek saglayici varken tema hareketleri
fun main() {
    val tree = themeTree()
    val providers = listOf("Screen")
    val moves = listOf("Title", "Label").map { reader ->
        Move("tema-$reader", closestTheme(tree, providers, reader), reader, tree)
    }
    for (move in moves) {
        move.describe()
    }
    countDirections(moves)
}
tema-Title: kimden=Screen | kime=Title -> derin
tema-Label: kimden=Screen | kime=Label -> derin
asagi: 0
yukari: 0
derin: 2
dis: 0

İki hareket de derin. Tema Screen’den çıkıp iki kat aşağıdaki metne ulaştı, aradaki düğümleri atlayarak. Hiçbir ara düğüm temayı bilmedi.

AD1. Model sağlayıcıları ad listesi olarak alır ve temanın içeriğini taşımaz. Hangi rengin, hangi yazı stilinin geldiği modelde yoktur; yalnız değerin hangi düğümden hangi düğüme gittiği ölçülür.

Alt Ağaç Kendi Temasını Sağlar

İkinci ölçümde Panel, kendi temasını sağlar; örneğin koyu bir paneldir. Title için hiçbir şey değişmez, ama Label için en yakın sağlayıcı artık Panel’dir.

// Main.kt — Panel kendi temasini saglarken
fun main() {
    val tree = themeTree()
    val providers = listOf("Screen", "Panel")
    val moves = listOf("Title", "Label").map { reader ->
        Move("tema-$reader", closestTheme(tree, providers, reader), reader, tree)
    }
    for (move in moves) {
        move.describe()
    }
    countDirections(moves)
}
tema-Title: kimden=Screen | kime=Title -> derin
tema-Label: kimden=Panel | kime=Label -> asagi
asagi: 1
yukari: 0
derin: 1
dis: 0

Title için hareket aynı kaldı: derin. Label için ise çıkış noktası kökten Panel’e geçti, ve Label panelin doğrudan çocuğu olduğundan hareket aşağı oldu. Aynı okuyucu, aynı tema nesnesi; ama sağlayıcı değişince yön değişti. Kökün temasını Label artık hiçbir yoldan almaz: araya giren sağlayıcı onu gölgeler.

AD2. Model bir okuyucunun tek bir sağlayıcıdan okuduğunu varsayar. Paneldeki bir değerin yalnız bir kısmını (örneğin yalnız rengi) değiştirip geri kalanını kökten bırakmak modelde yok.

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

Dersin yönü kökün temayı derindeki ögeye vermesinden gelir; panelin kendi sağlayıcılığı bunu daraltır. Aşağıdaki ölçüm üç hareket içerir: kökün başlığa verdiği tema, panelin etikete verdiği tema ve panelin kendi temasını nereden aldığı.

// Main.kt — panel kendi temasini saglarken uc hareket
fun main() {
    val tree = themeTree()
    val providers = listOf("Screen", "Panel")
    val moves = listOf(
        Move("baslik", closestTheme(tree, providers, "Title"), "Title", tree),
        Move("etiket", closestTheme(tree, providers, "Label"), "Label", tree),
        Move("panel-kaynagi", "Screen", "Panel", tree),
    )
    for (move in moves) {
        move.describe()
    }
    countDirections(moves)
}
baslik: kimden=Screen | kime=Title -> derin
etiket: kimden=Panel | kime=Label -> asagi
panel-kaynagi: kimden=Screen | kime=Panel -> asagi
asagi: 2
yukari: 0
derin: 1
dis: 0

panel-kaynagi 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 baslik ve etiket satırlarının sağlayıcı ucu closestTheme işlevinden gelir: derin 1, aşağı 1.

Bir derin, iki aşağı. Panelin temayı kökten türetmesi de, panelin etikete vermesi de doğrudan çocuğa gider. Derin olan tek hareket, aradaki Header düğümünü atlayan başlık temasıdır; yerel mekanizmasının asıl işi budur. Doğrudan çocuğa tema vermek için yerele gerek olmazdı: parametre yeterdi. Yerel, aradaki düğüm sayısı bilinmediğinde ya da değiştiğinde anlam kazanır. Dersin yönü: derin.

AD3. Model tema değişince ne olacağını ölçmez. Sağlayıcının değeri değiştiğinde onu okuyan işlevlerin yeniden çalışması ve bunun maliyeti bu derste ele alınmadı.

Özet

  • Bu dersin yönü: derin. Kökte sağlanan tema, aradaki Header düğümünü atlayarak başlığa ulaşır.
  • Tema ağacın bir noktasında sağlanır; altındaki her işlev onu okuyabilir.
  • Kökte sağlanan tema, aradaki düğümleri atlayarak derindeki metne ulaşır: derin.
  • Okuyucu için sağlayıcı, ataları arasındaki en yakın sağlayıcıdır.
  • Alt ağaç kendi temasını sağlarsa o ağaçtaki okuyucular için kök gölgelenir; doğrudan çocuğa giden değer aşağı gider.

Sonraki Adım

Tema, değerleri ağaçta sabit bir noktadan dağıtır. Animasyon ise değerin zamanla değişmesidir ve değişimi ağacın dışında bir saat sürer. Sonraki ders, kare saatinden gelen ara değerin ağaçta nereden geldiğini ve hedef değerin hangi yönde gittiğini ö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