Ders 13 / 17
Gezinme ve Rotalar
Rotayla seçilen hedefin gezinme bitene kadar arayüz ağacında bulunmamasının, bu yüzden hedefe giden argümanın önce dış, sonra aşağı gitmesinin ve geri dönen sonucun ölçümü.
Yayın Güncelleme
Bu derste
- Rotayı ayrıştırıp hedefi seçen bir modelin sonucunu ölçer
- Gezinme bitmeden hedefe giden argümanın ağaç dışında kaldığını gösterir
- Hedef ağaca girdikten sonra aynı argümanın aşağı gittiğini ayırt eder
- Geri dönüşte taşınan sonucun gezinme anında dış olduğunu açıklar
İçindekiler
Şimdiye kadar ölçülen her hareketin iki ucu da ağaçtaydı. Gezinmede bu değişir. Kullanıcı bir listeden ürün ayrıntısına geçtiğinde ayrıntı ekranı, geçişten önce ağaçta değildir. Ona götürülecek ürün numarası ise geçişin başlangıcında bellidir. Veri hedefinden önce vardır.
Bu ders, gezinme kabının (NavHost) bu boşluğu nasıl kapattığını ölçer. Rota hedefi seçer; hedef ağaca girer; argüman o zaman varır. Aynı argümanın iki anda iki farklı yön taşıması, bu dersin konusudur.
// 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 }}")
}
}
Rota, Hedef ve Geri Yığını
Gezinme düzeni üç parçadan oluşur. Gezinme denetleyicisi (NavController), hangi hedefte olunduğunu ve geri yığınını tutar. Gezinme kabı (NavHost) ağaçta durur ve o anki hedefin içeriğini çocuğu olarak çizer. Rota, bir hedefin metin adresidir; argüman rotanın içinde taşınır: detail/42, detail hedefine 42 argümanını götürür.
// Platform kodu: gezinme kabi, rotalar ve argumanli hedef
@Composable
fun AppNavigation(navController: NavHostController) {
NavHost(navController, startDestination = "list") {
composable("list") {
ProductList(onOpen = { id -> navController.navigate("detail/$id") })
}
composable("detail/{id}") { entry ->
ProductDetail(entry.arguments?.getString("id"))
}
}
}
navigate("detail/42") çağrıldığında platform rotayı ayrıştırır, uyan hedefi bulur, geri yığınına yeni bir kayıt ekler ve kabın içeriğini değiştirir. Hedefin içeriği ancak bu adımlardan sonra ağaca girer. ProductDetail o ana kadar hiçbir yerde çizilmiş değildir.
Model, platformun bu kuralını kurar; model platformun kendisi değildir. Yardımcı dosya rotayı ayrıştırıp bir hedef adı verir ve gezinme kabının altında bir hedefin bulunduğu ağacı kurar.
// Routes.kt — rota ayristirma ve hedef secimi (modelin hesabi)
class Route(val destination: String, val argument: String)
fun parseRoute(route: String): Route {
val parts = route.split("/")
return Route(parts[0], parts.getOrElse(1) { "" })
}
fun routeTarget(route: String, graph: List<String>): String? {
val destination = parseRoute(route).destination
return graph.firstOrNull { it.lowercase() == destination }
}
fun navTree(current: String): Tree =
Tree(mapOf("Screen" to "App", "NavHost" to "Screen", current to "NavHost"))
Gezinmeden Önce
İlk ölçümde ağaçta liste hedefi çizili. Kullanıcı detail/42 rotasına gitmek ister. Model rotayı ayrıştırır ve hedefi seçer; ama ağaç henüz gezinmeden önceki ağaçtır.
// Main.kt — gezinme baslamadan hedefe giden arguman
fun main() {
val graph = listOf("List", "Detail")
val route = "detail/42"
val target = routeTarget(route, graph) ?: return
println("hedef: $target")
println("arguman: ${parseRoute(route).argument}")
val before = navTree("List")
Move("arguman", "NavHost", target, before).describe()
}
hedef: Detail arguman: 42 arguman: kimden=NavHost | kime=Detail -> dis
Hedef Detail seçildi, argüman 42 ayrıştırıldı; ama Detail ağaçta olmadığı için hareket dış çıktı. Veri hazır, alıcı yok. Platform argümanı bu aralıkta geri yığınındaki kayıtta saklar; çizim başlayınca hedef onu oradan okur.
AD1. Model rotada en çok bir argüman taşır ve onu metin olarak bırakır. Platformun argüman türlerini, varsayılan değerlerini ve rotadaki sorgu parametrelerini ayrıştırması modelde yoktur.
Gezinmeden Sonra
İkinci ölçümde gezinme tamamlanmıştır: kabın altında artık Detail vardır. Aynı kaptan aynı hedefe aynı argüman gider.
// Main.kt — gezinme bittikten sonra arguman
fun main() {
val graph = listOf("List", "Detail")
val target = routeTarget("detail/42", graph) ?: return
val after = navTree(target)
Move("arguman", "NavHost", target, after).describe()
}
arguman: kimden=NavHost | kime=Detail -> asagi
Aynı iki uç, bu kez aşağı. Hedef ağaca girdiği için kabın doğrudan çocuğudur. Değişen yalnız ağaçtır: veri, kaynak ve hedef aynı.
AD2. Model gezinmeyi tek adımda, ağacın bir anda öncesinden sonrasına geçmesi olarak kurar. Platformdaki geçiş animasyonu sırasında eski ve yeni hedefin aynı anda ağaçta bulunması modelde yoktur.
Geri Dönen Sonuç
Gezinme tek yönlü değildir. Kullanıcı ayrıntıdan geri döndüğünde ayrıntı ekranı ağaçtan çıkar ve liste yeniden çizilir. Ayrıntı ekranı bir sonuç bırakmışsa, örneğin ürün sepete eklendiğini, bu sonuç listeye geri yığınındaki kayıt üzerinden ulaşır. Sonucun yazıldığı an ayrıntı ekranı hâlâ ağaçtadır, ama liste okuduğunda ayrıntı çoktan gitmiştir.
// Main.kt — geri donuste ayrintinin biraktigi sonuc
fun main() {
val back = navTree("List")
Move("sonuc", "Detail", "List", back).describe()
}
sonuc: kimden=Detail | kime=List -> dis
Bu satırı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. Geri dönen sonucun dış olması, gönderen ucu routeTarget çıktısı olan sınırlayıcı ölçümdeki sonuc satırına da dayanır.
Dış. Geri dönüş tamamlandığında gönderen düğüm ağaçta yoktur. Sonuç ağaç üzerinden değil, gezinme denetleyicisinin tuttuğu kayıt üzerinden taşınır. Argüman ileri gezinmede, sonuç geri gezinmede ağaç dışıdır; her ikisi de geçişin iki yanından birinde ağaçta bulunmayan bir uca bağlıdır.
AD3. Model sonucu yalnız geri dönüş anından ölçer. Sonucun ayrıntı ekranı hâlâ ağaçtayken yazıldığı an modelde ayrı bir hareket olarak kurulmadı.
Sınırlayıcı Ölçüm
Dersin yönü, argümanın gezinmenin öncesi ve sonrasında nasıl bölündüğünden çıkar. Aşağıdaki ölçüm dört hareketi birlikte gösterir: ekranın gezinme kabına verdiği başlangıç rotası, gezinme öncesi argüman, gezinme sonrası argüman, geri dönen sonuç.
// Main.kt — gezinmenin dort hareketi
fun main() {
val graph = listOf("List", "Detail")
val target = routeTarget("detail/42", graph) ?: return
val before = navTree("List")
val after = navTree(target)
val moves = listOf(
Move("baslangic-rotasi", "Screen", "NavHost", before),
Move("arguman-once", "NavHost", target, before),
Move("arguman-sonra", "NavHost", target, after),
Move("sonuc", target, "List", before),
)
for (move in moves) {
move.describe()
}
countDirections(moves)
}
baslangic-rotasi: kimden=Screen | kime=NavHost -> asagi arguman-once: kimden=NavHost | kime=Detail -> dis arguman-sonra: kimden=NavHost | kime=Detail -> asagi sonuc: kimden=Detail | kime=List -> dis asagi: 2 yukari: 0 derin: 0 dis: 2
baslangic-rotasi 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 üç satırın bir ucu routeTarget çıktısıdır: aşağı 1, dış 2.
İki aşağı, iki dış. Başlangıç rotası ve gezinmeden sonraki argüman, ağaçtaki iki bağlı düğüm arasında olduğu için aşağı gitti. Gezinmeden önceki argüman ve geri dönen sonuç, bir ucu ağaçta olmadığı için dış kaldı. Gezinme, ağaç dışı iki hareketi yönetmek için vardır; yön, hareketin hangi anda ölçüldüğüne bağlıdır. Dersin yönü: dış.
AD4. Model dört hareketi ağacın iki anından alır. Platformda bu anlar arasında geçen sürenin, argümanın hangi kayıtta durduğunun ya da süreç yeniden başlayınca neyin korunduğunun ölçümü bu derste yok.
Özet
- Bu dersin yönü: dış. Gezinmeden önceki argüman ve geri dönen sonuç, ağaçta bulunmayan bir uca bağlıdır.
- Rota hedefin metin adresidir; argüman rotanın içinde taşınır.
- Gezinme bitmeden hedef ağaçta değildir, bu yüzden ona giden argüman dıştır.
- Hedef ağaca girince aynı argüman kabın çocuğuna aşağı gider.
- Geri dönen sonuç, gönderen ağaçtan çıktıktan sonra okunduğu için dıştır.
Sonraki Adım
Gezinme hangi içeriğin çizileceğini seçer, tema ise çizilen her içeriğin nasıl görüneceğini belirler. Sonraki ders, kökte seçilen temanın derindeki metne kadar nasıl indiğini ve alt ağacın kendi temasını sağladığında yönün nasıl değiştiğini ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.