Diğer kullanıcı arayüzü araç setlerinin çoğunda olduğu gibi, Compose'da da birden fazla farklı aşamalar bulunmaktadır. Android View sistemine bakacak olursak, üç temel aşamalarından oluşur: ölçme, düzenleme ve çizim. Oluşturma çok benzer ancak bileşim adı verilen önemli bir ek aşamayı oluşturur.
Beste, Thinking in Compose ve State ve Jetpack Compose.
Bir karenin üç aşaması
Oluşturmanın üç ana aşaması vardır:
- Beste: Hangi kullanıcı arayüzü gösterilecek? Compose, composable işlevleri çalıştırır ve kullanıcı arayüzünüzle ilgili bir açıklama oluşturur.
- Düzen: Kullanıcı arayüzünün yerleştirileceği yer. Bu aşama iki adımdan oluşur: ölçüm ve yerleşim. Düzen öğeleri kendilerini ölçer, yerleştirir ve her düğüm için 2D koordinatlardaki alt öğeleri görebilirsiniz.
- Çizim: Nasıl oluşturulur? Kullanıcı arayüzü öğeleri bir Tuvale, genellikle cihaz ekranına gidin.
![Compose'un verileri kullanıcı arayüzüne dönüştürdüğü üç aşamanın (sırayla veri, kompozisyon, düzen, çizim, kullanıcı arayüzü) resmi.](https://developer.android.com/static/develop/ui/compose/images/compose-phases.png?authuser=5&hl=tr)
Bu aşamaların sırası genellikle aynıdır ve verilerin tek bir aşamada akışına izin verir.
bir kare üretmek için bileşimden düzene ve çizime kadar her yönüyle
tek yönlü veri akışı olarak ayarlayın.
BoxWithConstraints
ve
LazyColumn
ve LazyRow
önemli noktalar
üst öğelerinin bileşimi üst yayıncının düzenine bağlı olan istisnalar
aşamasındayız.
Bu üç aşamanın her kare için sanal olarak gerçekleştiğini varsayabilirsiniz. Ancak daha iyi bir performans elde etmek için Compose, tüm bu aşamalarda aynı girişlerden aynı sonuçları hesaplamalısınız. Oluştur atlayabilirsiniz. işlevini çağırıyorsa ve Oluştur kullanıcı arayüzü yeniden düzen vermiyorsa veya ağacın tamamını yeniden çizebilirsiniz. Oluşturma işlemi yalnızca kullanıcı arayüzünü güncellemek için gereken minimum çalışma miktarıdır. Bu optimizasyon, çünkü Oluştur, farklı aşamalardaki durum okumalarını izler.
Aşamaları anlama
Bu bölümde, composable'lar için üç Compose aşamasının nasıl yürütüldüğü açıklanmaktadır ayrıntılı olarak inceleyelim.
Beste
Beste aşamasında, Compose çalışma zamanı composable işlevleri yürütür kullanıcı arayüzünüzü temsil eden bir ağaç yapısı gösterir. Bu kullanıcı arayüzü ağacı şunları içerir: sonraki aşamalar için gereken tüm bilgileri içeren düzen düğümlerini aşağıdaki videoda gösteriliyor:
Şekil 2. Bestede oluşturulan kullanıcı arayüzünü temsil eden ağaç aşamasındayız.
Kod ve kullanıcı arayüzü ağacının alt bölümü aşağıdaki gibi görünür:
![Beş composable'ı içeren kod snippet'i ve ortaya çıkan kullanıcı arayüzü ağacı, alt düğümlerin üst düğümlerinden dallandığı gibi.](https://developer.android.com/static/develop/ui/compose/images/code-subsection.png?authuser=5&hl=tr)
Bu örneklerde, koddaki her composable işlevi tek bir düzene eşlenir kullanıcı arayüzü ağacında. Daha karmaşık örneklerde composable'lar mantık ve ve farklı durumlara göre farklı bir ağaç üretmeyi öğreneceksiniz.
Düzen
Compose, düzen aşamasında beste aşamasında oluşturulan kullanıcı arayüzü ağacını kullanır giriş olarak kullanabilirsiniz. Düzen düğümleri koleksiyonu, 2D uzayda her düğümün boyutuna ve konumuna karar verme.
4.Şekil Düzen aşamasında, kullanıcı arayüzü ağacındaki her bir düzen düğümünün ölçümü ve yerleşimi.
Düzen aşamasında, ağaçta aşağıdaki üç adım kullanılarak geçilir algoritma:
- Alt öğeleri ölç: Bir düğüm, varsa alt öğelerini ölçer.
- Kendi boyutuna karar verme: Bu ölçümlere göre düğüm kendi başına karar verir. seçin.
- Alt öğeleri yerleştir: Her alt düğüm, bir düğümün kendi öğesine göre yerleştirilir. dokunun.
Bu aşamanın sonunda, her düzen düğümü:
- Atanan width ve height
- Çizilmesi gereken x, y koordinatı
Önceki bölümde verilen kullanıcı arayüzü ağacını geri çağırın:
Bu ağaç için algoritma aşağıdaki gibi çalışır:
Row
,Image
veColumn
olmak üzere alt öğelerini ölçer.Image
ölçülür. Hiç çocuğu yok, bu yüzden kendi kararını verir. ve boyutuRow
özelliğine geri bildirir.- Ardından
Column
ölçülür. Kendi alt öğelerini ölçer (ikiText
composables) emin olun. - İlk
Text
ölçülmüştür. Hiç çocuğu yok, bu yüzden ve boyutunuColumn
değerine geri bildirir.- İkinci
Text
ölçülür. Hiç çocuğu yok, bu yüzden veColumn
parametresine geri bildirir.
- İkinci
Column
, kendi boyutuna karar vermek için alt ölçümleri kullanır. Şunu kullanır: alt öğelerinin yüksekliğinin toplamıdır.Column
, çocuklarını kendisiyle göreli olarak yerleştirir ve birbirlerine bağladık.Row
, kendi boyutuna karar vermek için alt ölçümleri kullanır. Şunu kullanır: maksimum alt öğe yüksekliği ve alt öğelerinin genişliklerinin toplamı. Bu durumda yardımcı olur.
Her düğümün yalnızca bir kez ziyaret edildiğini unutmayın. Compose çalışma zamanı için yalnızca bir tüm düğümleri ölçmek ve yerleştirmek için kullanıcı arayüzü ağacından geçmek, bu da bazı yolları da görmüştük. Ağaçtaki düğüm sayısı arttıkça harcanan zaman doğrusal bir şekilde artacaktır. Bunun aksine her bir düğüm ziyaret süresi katlanarak artar.
Çizim
Çizim aşamasında, ağaç tekrar yukarıdan aşağıya doğru çaprazlanır ve her bir çizim önce kendisini ekranda çizer.
5. Şekil. Çizim aşaması, pikselleri ekranda çizer.
Önceki örnekte, ağaç içeriği aşağıdaki şekilde çizilir:
Row
, arka plan rengi gibi olası içeriği çizer.Image
kendini çeker.Column
kendini çeker.- Sırasıyla birinci ve ikinci
Text
, kendilerini çizer.
6. Şekil. Kullanıcı arayüzü ağacı ve çizilmiş temsili.
Durum okumaları
Bir sırasında anlık görüntü durumunun değerini okuduğunuzda sıralandığı aşamalardan birini izlerseniz, Compose'da ilk olarak değer okundu. Bu izleme, aşağıdaki durumlarda Compose'un okuyucuyu yeniden çalıştırmasına olanak tanır: durum değeri değişir ve Compose'daki durum gözlemlenebilirliğinin temelini oluşturur.
Durum, genellikle mutableStateOf()
kullanılarak oluşturulur ve daha sonra bir üzerinden erişilir
iki yöntem vardır: value
mülküne doğrudan erişerek veya
yeni bir kod oluşturabilirsiniz. Bunlar hakkında daha fazla bilgiyi Şurada bulabilirsiniz:
composables olarak da bilinir. Şu amaçlara yönelik olarak:
bir "eyalet okuma durumu" söz konusu eş değer erişimlerden herhangi birini
yöntemlerine göz atın.
// State read without property delegate. val paddingState: MutableState<Dp> = remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(paddingState.value) )
// State read with property delegate. var padding: Dp by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(padding) )
Mülkün gelişmiş özellikleri
yetki verin,
"alıcı" ve "setter" fonksiyonları Eyaletin verilerine erişmek ve bunları güncellemek için
value
. Bu alıcı ve belirleyici işlevleri yalnızca
özelliği oluşturulduğunda değil, değer olarak göstermektir; bu nedenle,
yukarıdakiler eşdeğerdir.
Okuma durumu değiştiğinde yeniden yürütülebilecek her bir kod bloğu yeniden başlatma kapsamına girer. Oluşturma, durum değeri değişikliklerini takip eder ve yeniden başlatır farklı aşamalarda durumlarla karşılaşabilirsiniz.
Aşamalı durum okumaları
Yukarıda belirtildiği gibi, Oluşturma ve Oluşturma parçalarında üç ana aşama bulunur hangi durumun okunduğunu görebiliriz. Bu işlem, Compose'un yalnızca projenizdeki her unsur için gereken çalışmaları yapması gereken Kullanıcı arayüzü.
Her bir aşamayı ele alalım ve bir durum değeri okunduğunda ne olduğunu açıklayalım. bir bilgidir.
1. Aşama: Beste
@Composable
işlevi veya lambda bloğu içindeki durum okumaları bileşimi etkiler
sonraki aşamaları da içerebilir. Durum değeri değiştiğinde,
recomposer programı,
durum değeri. Çalışma zamanının, bu reklamların bazılarını ya da tamamını atlamasına
composable işlevlerini kullanabilirsiniz. Girişler varsa atlama
değişmedi bölümünü ziyaret edin.
Oluşturma kullanıcı arayüzü, kompozisyonun sonucuna bağlı olarak düzeni ve çizimi çalıştırır. aşamalar. İçerik aynı ve boyut aynı kalırsa bu aşamaları atlayabilir. ve düzen de değişmez.
var padding by remember { mutableStateOf(8.dp) } Text( text = "Hello", // The `padding` state is read in the composition phase // when the modifier is constructed. // Changes in `padding` will invoke recomposition. modifier = Modifier.padding(padding) )
2. Aşama: Düzen
Düzen aşaması iki adımdan oluşur: ölçüm ve yerleşim. İlgili içeriği oluşturmak için kullanılan
ölçüm adımı, Layout
composable'a iletilen ölçü lambda'yı çalıştırır.
LayoutModifier
arayüzünün MeasureScope.measure
yöntemi vb. İlgili içeriği oluşturmak için kullanılan
yerleşim adımı, layout
işlevinin yerleşim bloğunu (lambda) çalıştırır.
Modifier.offset { … }
bloğu vb.
Bu adımların her biri sırasındaki durum okumaları, düzeni ve potansiyel olarak aşamasındayız. Durum değeri değiştiğinde Compose kullanıcı arayüzü, düzeni programlar aşamasındayız. Ayrıca boyut veya konum değişirse çizim aşamasını da çalıştırır.
Daha kesin konuşmak gerekirse ölçüm adımı ile yerleşim kapsamları yeniden başlatma: yerleşim adımındaki durum okumaları yeniden çağrılmaz adım adım ilerleyelim. Ancak bu iki adım çoğu zaman iç içe geçmiş olduğundan, yerleşim adımında okunan bir durum diğer yeniden başlatmaları etkileyebilir kapsamlarını belirleyebilirsiniz.
var offsetX by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.offset { // The `offsetX` state is read in the placement step // of the layout phase when the offset is calculated. // Changes in `offsetX` restart the layout. IntOffset(offsetX.roundToPx(), 0) } )
3. Aşama: Çizim
Çizim kodu sırasındaki durum okumaları çizim aşamasını etkiler. Yaygın örnekler
Canvas()
, Modifier.drawBehind
ve Modifier.drawWithContent
dahil. Zaman
durum değeri değiştiğinde, Oluştur kullanıcı arayüzü yalnızca çizim aşamasını çalıştırır.
var color by remember { mutableStateOf(Color.Red) } Canvas(modifier = modifier) { // The `color` state is read in the drawing phase // when the canvas is rendered. // Changes in `color` restart the drawing. drawRect(color) }
Durum okumalarını optimize etme
Compose, yerelleştirilmiş durum okuma izlemesi yaptığında, gerçekleştirilen çalışmadan elde edilen gelir ve çalışma şeklinin her durumu uygun aşamada okunarak.
Bir örnekle açıklayalım. Burada, ofset kullanan bir Image()
değiştiricisi, son düzen konumunu dengelemek ve böylece
Kullanıcı sayfayı kaydırır.
Box { val listState = rememberLazyListState() Image( // ... // Non-optimal implementation! Modifier.offset( with(LocalDensity.current) { // State read of firstVisibleItemScrollOffset in composition (listState.firstVisibleItemScrollOffset / 2).toDp() } ) ) LazyColumn(state = listState) { // ... } }
Bu kod çalışır ancak optimum olmayan performansa neden olur. Yazıldığı gibi, kod
firstVisibleItemScrollOffset
durumunun değerini okur ve bunu
"the"
Modifier.offset(offset: Dp)
işlevini kullanın. Kullanıcı sayfayı kaydırdıkça firstVisibleItemScrollOffset
değeri
unutmayın. Bildiğimiz gibi Compose, yeniden başlatılabilmesi için tüm durum okumalarını izler
okuma kodunu (yeniden çağırın) tıklayın. Bu örnekteki değerimiz,
Box
Bu, beste aşamasında okunan bir durum örneğidir. Bu kesinlikle kötü bir şey değil. Aslında yeniden düzenlemenin temelini oluşturur. veri değişikliklerinin yeni kullanıcı arayüzü yayınlamasına izin verir.
Bu örnekte optimum değildir, çünkü her kaydırma etkinliği yeniden değerlendiriliyor ve ardından ölçülmesi gerekiyor. zemini hazırladık. Her kaydırmada Oluşturma aşamasını tetikliyoruz Gösterilen ne değişmemiş olsa da yalnızca nerede gösterildiğine bağlıdır. Durum okuma işlemini yalnızca düzen aşamasını yeniden tetikleyecek şekilde optimize edebiliriz.
Ofset değiştiricinin başka bir sürümü de mevcuttur:
Modifier.offset(offset: Density.() -> IntOffset)
.
Bu sürüm bir lambda parametresi alır; burada elde edilen ofset lambda bloğunu. Kullanılacak kodumuzu güncelleyelim:
Box { val listState = rememberLazyListState() Image( // ... Modifier.offset { // State read of firstVisibleItemScrollOffset in Layout IntOffset(x = 0, y = listState.firstVisibleItemScrollOffset / 2) } ) LazyColumn(state = listState) { // ... } }
Peki, bu neden daha iyi performans gösteriyor? Değiştiriciye sağladığımız lambda bloğu
düzen aşamasında (özellikle de yerleşim aşaması sırasında
yerleşim adımı), yani firstVisibleItemScrollOffset
durumumuz
daha uzun okumalarını sağlar. E-posta, durum okunduğunda izleme yaptığı için
bu değişiklik, firstVisibleItemScrollOffset
değeri değişirse
Oluşturmak için düzen ve çizim aşamalarının yeniden başlatılması yeterlidir.
Bu örnek, ofset parametresini optimize edebilmek için farklı ofset değiştiricilerine bir sonuç elde edersiniz, ancak genel fikir doğrudur: Durum okumalarını mümkün olan en düşük aşamayı, yani Compose'un mümkün olan en az miktarda iş yeri.
Elbette, çoğu zaman bestedeki durumları okumak aşamasındayız. Yine de, aramızdaki iletişimin sayısını en aza yeniden bestelemenize olanak tanır. Bununla ilgili daha fazla bilgi için bakın derivedStateOf: bir veya birden fazla durum nesnesini diğerine dönüştürme durum.
Yeniden oluşturma döngüsü (döngüsel aşama bağımlılığı)
Daha önce, Compose'un aşamalarının her zaman aynı emin olmanız ve aynı karede geri gitmek mümkün değildir. Ancak bu, uygulamaların beste döngülerine dahil edilmesini yasaklamaz farklı karelerde kullanılabilir. Aşağıdaki örneğe bakın:
Box { var imageHeightPx by remember { mutableStateOf(0) } Image( painter = painterResource(R.drawable.rectangle), contentDescription = "I'm above the text", modifier = Modifier .fillMaxWidth() .onSizeChanged { size -> // Don't do this imageHeightPx = size.height } ) Text( text = "I'm below the image", modifier = Modifier.padding( top = with(LocalDensity.current) { imageHeightPx.toDp() } ) ) }
Burada, resmin en üstte olduğu dikey bir sütun uyguladık (kötü bir şekilde)
altındaki metin de görünür. Şunları bilmek için Modifier.onSizeChanged()
kullanıyoruz:
ve ardından çözüm olarak metinde Modifier.padding()
kullanarak
aşağı kaydırın. Px
ile Dp
tarihleri arasındaki yapay dönüşüm zaten
kodda bir sorun olduğunu gösterir.
Bu örnekteki sorun, nihai sonuca ulaşmadığımız düzen içinde olduğunu unutmayın. Kod, gerçekleşen birden fazla kareye dayanır ve bu kareler kullanıcı arayüzü, kullanıcı için ekranda sürekli olarak atlanır.
Neler olduğunu görmek için her bir kareyi tek tek inceleyelim:
İlk karenin beste aşamasında imageHeightPx
değeri 0,
ve metin Modifier.padding(top = 0)
ile sağlanır. Ardından, düzen
aşaması devam eder ve onSizeChanged
değiştiricisi için geri çağırma çağrılır.
Bu işlemde imageHeightPx
, resmin gerçek yüksekliğine güncellenir.
Sonraki kare için yeniden besteleme programları oluşturun. Çizim aşamasında,
değer değişikliği yansıtılmadığından metin, 0 dolgusuyla oluşturulur
(henüz).
Oluştur, ardından şu değer değişikliğine göre programlanan ikinci kareyi başlatır:
imageHeightPx
Durum, Box içerik bloğunda okunur ve çağrılır
aşamasına geçelim. Bu kez metin bir dolguyla sağlanır
resim yüksekliğiyle eşleşiyor. Düzen aşamasında bu kod,
Tekrar imageHeightPx
, ancak değerden bu yana yeniden düzenleme planlanmadı
aynı kalır.
Sonunda metinde istenen dolguyu alırız ancak bu dolgunun dolgu değerini farklı bir aşamaya geri aktarmak için fazladan bir kare harcamasını çakışan içeriğe sahip bir kare oluşturulmasıyla sonuçlanır.
Bu örnek biraz çelişkili görünebilir, ancak şu genel örüntüye dikkat edin:
Modifier.onSizeChanged()
,onGloballyPositioned()
veya başka bir düzen işlemler- Bir eyaleti güncelle
- Bu durumu düzen değiştiricide giriş olarak kullan (
padding()
,height()
veya benzer) - Tekrarlama ihtimali var
Yukarıdaki örneğin çözümü, uygun düzen temel öğelerini kullanmaktır. Örnek
yukarıdaki basit bir Column()
ile uygulanabilir, ancak daha fazla
özel bir işlem gerektiren karmaşık bir örnek teşkil ediyor. Bu da
özel düzen. Özel düzenler kılavuzunu inceleyin
konulu videomuzu izleyin.
Buradaki genel ilke, birden fazla kullanıcı arayüzü için tek bir doğruluk kaynağına sahip olmaktır ölçülmesi ve yerleştirilmesi gereken unsurlardır. Kullanım bir düzen temel öğesi oluşturmak veya özel bir düzen oluşturmak, ortak ebeveyn, ilişki ve korelasyon arasındaki ilişkiyi koordine eden bilgi kaynağı işlevi görür ekleyebilirsiniz. Dinamik bir durumun uygulanması bu ilkeyi çiğnemektedir.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- State ve Jetpack Compose
- Listeler ve ızgaralar
- Jetpack Compose için Kotlin