CompositionLocal
, şunlar için bir araçtır:
Dolaylı olarak Beste'den
aşağıya doğru aktarılır. Bu sayfada
CompositionLocal
ne olduğunu daha ayrıntılı olarak, kendi şablonunuzu nasıl oluşturacağınızı öğrenin
CompositionLocal
ve CompositionLocal
çözümünün aşağıdakiler için iyi bir çözüm olup olmadığını öğrenin
en iyi uygulamaları görelim.
CompositionLocal
ile tanışın
Compose'da genellikle veriler akıştan Her composable işlevin parametreleri olarak kullanıcı arayüzü ağacı. Bu, bir composable'ın açıklığa kavuşturmaktır. Ancak bu, çok büyük boyutlu ve yaygın olarak kullanılır. Aşağıdakilere göz atın örnek:
@Composable fun MyApp() { // Theme information tends to be defined near the root of the application val colors = colors() } // Some composable deep in the hierarchy @Composable fun SomeTextLabel(labelText: String) { Text( text = labelText, color = colors.onPrimary // ← need to access colors here ) }
Renkleri
Compose teklifleri CompositionLocal
sayesinde
kullanarak örtülü bir yöntem olarak kullanılabilecek ağaç kapsamlı adlandırılmış nesneler oluşturmak
kullanıcı arayüzü ağacı üzerinden veri akışı sağlanıyor.
CompositionLocal
öğeleri genellikle belirli bir düğümde bir değerle sağlanır
örneğidir. Bu değer, composable alt öğeleri tarafından
CompositionLocal
, composable işlevde parametre olarak tanımlanıyor.
Materyal teması, arka planda CompositionLocal
kullanır.
MaterialTheme
üç CompositionLocal
örneği sağlayan bir nesne: colorScheme
,
typography
ve shapes
; bunları daha sonra herhangi bir alt öğede almanıza olanak tanır
bölümü için de geçerlidir.
Bunlar LocalColorScheme
, LocalShapes
ve
MaterialTheme
üzerinden erişebileceğiniz LocalTypography
mülk
colorScheme
, shapes
ve typography
özellikleri.
@Composable fun MyApp() { // Provides a Theme whose values are propagated down its `content` MaterialTheme { // New values for colorScheme, typography, and shapes are available // in MaterialTheme's content lambda. // ... content here ... } } // Some composable deep in the hierarchy of MaterialTheme @Composable fun SomeTextLabel(labelText: String) { Text( text = labelText, // `primary` is obtained from MaterialTheme's // LocalColors CompositionLocal color = MaterialTheme.colorScheme.primary ) }
CompositionLocal
örneği Beste'nin bir kısmına ayarlanır. Böylece,
ağacın farklı düzeylerinde farklı değerler sağlayabilir. current
değeri
bir CompositionLocal
,
bestedeki bir üst öğe olarak kabul edilir.
CompositionLocal
öğesine yeni bir değer sağlamak için
CompositionLocalProvider
ve onun provides
CompositionLocal
anahtarını value
ile ilişkilendiren infix işlevi. İlgili içeriği oluşturmak için kullanılan
Sağlanan CompositionLocalProvider
, content
lambda'yı alacak
değeri için current
ve CompositionLocal
özelliğine erişirsiniz. Bir
yeni değer sağlandığında, Compose, Beste'nin şu okunan kısımlarını yeniden
CompositionLocal
.
Buna bir örnek olarak, LocalContentColor
CompositionLocal
metin ve
kullanarak mevcut arka plan rengiyle kontrast oluşturun.
aşağıdaki örnekte CompositionLocalProvider
, farklı erişim düzeyleri sağlamak için
değerleri oluşturabilirsiniz.
@Composable fun CompositionLocalExample() { MaterialTheme { // Surface provides contentColorFor(MaterialTheme.colorScheme.surface) by default // This is to automatically make text and other content contrast to the background // correctly. Surface { Column { Text("Uses Surface's provided content color") CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.primary) { Text("Primary color provided by LocalContentColor") Text("This Text also uses primary as textColor") CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.error) { DescendantExample() } } } } } } @Composable fun DescendantExample() { // CompositionLocalProviders also work across composable functions Text("This Text uses the error color now") }
Şekil 1. CompositionLocalExample
composable'ın önizlemesi.
Son örnekte, CompositionLocal
örnekleri dahili olarak kullanılmıştır.
Material composable'dan oluşacak. Bir CompositionLocal
öğesinin mevcut değerine erişmek için
current
kullanın
Aşağıdaki örnekte LocalContext
öğesinin mevcut Context
değeri
Android uygulamalarında yaygın olarak kullanılan CompositionLocal
, biçimlendirmek için kullanılır
metin:
@Composable fun FruitText(fruitSize: Int) { // Get `resources` from the current value of LocalContext val resources = LocalContext.current.resources val fruitText = remember(resources, fruitSize) { resources.getQuantityString(R.plurals.fruit_title, fruitSize) } Text(text = fruitText) }
Kendi CompositionLocal
oluşturma
CompositionLocal
, Beste’den aşağıya veri aktarmak için kullanılan bir araçtır
dolaylı olarak oluşturabilirsiniz.
CompositionLocal
kullanmak için bir diğer önemli sinyal, parametrenin
kesişim ve ara uygulama katmanlarının farkında olmalısınız.
vardır, çünkü bu ara katmanların farkında olmaları
fayda sağlar. Örneğin, Android izinlerini sorgulamak için
bu araçlar arasında yer alan bir CompositionLocal
bulunur. Bir medya seçici composable
izinle korunan içeriklere erişmek için
API'sini değiştirmeden ve medya seçiciyi arayanların
ortamdan kullanılan bu ek bağlamın farkında olun.
Ancak, CompositionLocal
her zaman en iyi çözüm değildir. Biz
Bazı dezavantajları beraberinde getirdiği için CompositionLocal
'ın aşırı kullanımının önüne geçin:
CompositionLocal
, bir composable'ın davranışının akıl yürütmesini zorlaştırır. Farklı
örtülü bağımlılıklar oluşturuyorlar. Bunları kullanan composable’ları kullananlar da
her CompositionLocal
için bir değere uygun olduğundan emin olun.
Dahası, bu bağımlılığın açık ve doğru bir kaynağı olmayabilir.
Kompozisyonun herhangi bir bölümünde değişebilir. Dolayısıyla, bir istek olduğunda uygulamadaki
daha zor olabilir, çünkü bu işlemi gerçekleştirmeniz
current
değerinin nerede sağlandığını görmek için beste. Find gibi araçlar
kullanımları IDE veya Oluşturma düzen denetleyicisi'ndeki
olabileceğini unutmayın.
CompositionLocal
kullanılıp kullanılmayacağına karar veriliyor
CompositionLocal
uygulamasını iyi bir çözüm haline getirebilecek belirli koşullar vardır
bir örneği inceleyelim:
CompositionLocal
iyi bir varsayılan değere sahip olmalıdır. Varsayılan ayar yoksa
bir geliştirici için bunu yapmanın çok zor olduğunu
CompositionLocal
için bir değerin sağlanmadığı durumlarla karşılaşabilirsiniz.
Varsayılan bir değer sağlanmaması,
testlerde veya CompositionLocal
öğesini kullanan bir composable'ın önizlemesi
bu değerin açıkça sağlanmasını gerekli kılmaz.
Ağaç kapsamlı veya ağaç kapsamlı olarak düşünülmeyen kavramlar için CompositionLocal
alt hiyerarşi kapsamındaki CompositionLocal
, mümkün olduğunda anlam ifade eder
birkaç alt öğe tarafından kullanıldığı düşünülebilir.
Kullanım alanınız bu şartları karşılamıyorsa
Oluşturmadan önce Dikkate alınacak alternatifler bölümü
CompositionLocal
.
Kötü uygulamalara örnek olarak,CompositionLocal
Belirli bir ekranın ViewModel
kadarını ekleyebilirsiniz. Böylece o ekrandaki tüm composable'lar,
bir mantık yürütmek için ViewModel
öğesine referans alın. Bu kötü bir uygulama
çünkü belirli bir kullanıcı arayüzü ağacının altındaki tüm composable'ların
ViewModel
İyi uygulama, yalnızca composable'lara bilgileri
durumun aşağı, etkinliklerin yukarı akışı kalıbına uymaları gerekir. Bu yaklaşım, composable'larınızı daha verimli
ve daha kolay test edilebilir.
CompositionLocal
oluşturuluyor
CompositionLocal
oluşturmak için iki API vardır:
compositionLocalOf
: Yeniden oluşturma sırasında sağlanan değerin değiştirilmesi yalnızca geçersiz kılınır şu mesajı okuyan içerik:current
değer.staticCompositionLocalOf
:compositionLocalOf
işlevinin aksine,staticCompositionLocalOf
okumaları Compose tarafından takip edilir. Değerin değiştirilmesi,content
ayarının tamamen değişmesine neden olur. yerineCompositionLocal
öğesinin yeniden oluşturulmasının sağlandığı lambda yalnızcacurrent
değerinin Beste'de okunduğu yerlerdir.
CompositionLocal
için sağlanan değerin değişme olasılığı düşükse veya
asla değişmeyecek. Performans avantajlarından yararlanmak için staticCompositionLocalOf
kullanın.
Örneğin, bir uygulamanın tasarım sistemi, composable'ların
değeri, kullanıcı arayüzü bileşeni için bir gölge kullanılarak yükseltilir. Farklı
yükseltileri kullanıcı arayüzü ağacına yayılmalıdır. Bir
CompositionLocal
CompositionLocal
değeri koşullu olarak türetildiğinden
sistem temasına göre compositionLocalOf
API'yi kullanıyoruz:
// LocalElevations.kt file data class Elevations(val card: Dp = 0.dp, val default: Dp = 0.dp) // Define a CompositionLocal global object with a default // This instance can be accessed by all composables in the app val LocalElevations = compositionLocalOf { Elevations() }
CompositionLocal
için değer sağlama
CompositionLocalProvider
composable, belirtilen değer için değerleri CompositionLocal
örneğine bağlar
hiyerarşi. Bir CompositionLocal
için yeni bir değer sağlamak üzere
provides
CompositionLocal
anahtarını aşağıdaki şekilde bir value
ile ilişkilendiren infix işlevi:
// MyActivity.kt file class MyActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { // Calculate elevations based on the system theme val elevations = if (isSystemInDarkTheme()) { Elevations(card = 1.dp, default = 1.dp) } else { Elevations(card = 0.dp, default = 0.dp) } // Bind elevation as the value for LocalElevations CompositionLocalProvider(LocalElevations provides elevations) { // ... Content goes here ... // This part of Composition will see the `elevations` instance // when accessing LocalElevations.current } } } }
CompositionLocal
kullanımı
CompositionLocal.current
, söz konusu CompositionLocal
için bir değer sağlayan en yakın CompositionLocalProvider
tarafından sağlanan değeri döndürür:
@Composable fun SomeComposable() { // Access the globally defined LocalElevations variable to get the // current Elevations in this part of the Composition MyCard(elevation = LocalElevations.current.card) { // Content } }
Değerlendirilebilecek alternatifler
CompositionLocal
, bazı kullanım alanları için aşırı bir çözüm olabilir. Eğer
kullanım alanı kullanılıp kullanılmayacağına karar verme
CompositionLocal bölümü gibi başka bir çözüm muhtemelen daha iyi olabilir
bir şablon görevi görür.
Açık parametreleri iletme
composable'ın bağımlılıklarını açıkça belirtmek iyi bir alışkanlıktır. Önerilerimiz: composable'ları yalnızca ihtiyaç duydukları şeyleri iletin. Ayrıştırmayı teşvik etmek için ve yeniden kullanılması gereken composable'ların her biri, en az bilgi sağlar.
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... MyDescendant(myViewModel.data) } // Don't pass the whole object! Just what the descendant needs. // Also, don't pass the ViewModel as an implicit dependency using // a CompositionLocal. @Composable fun MyDescendant(myViewModel: MyViewModel) { /* ... */ } // Pass only what the descendant needs @Composable fun MyDescendant(data: DataToDisplay) { // Display data }
Kontrolü ters çevirme
Gereksiz bağımlılıkları bir composable'a iletmekten kaçınmanın bir yolu da kontrolü ters çevirme yoluyla yapılır. Bir bağımlılığın yerine ana yayıncı belirli bir mantık yürütür.
Bir alt öğenin şu isteği tetiklemesi gereken aşağıdaki örneğe bakın: Bazı verileri yükleyin:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... MyDescendant(myViewModel) } @Composable fun MyDescendant(myViewModel: MyViewModel) { Button(onClick = { myViewModel.loadData() }) { Text("Load data") } }
Duruma bağlı olarak MyDescendant
adlı kuruluşun büyük sorumluluğu olabilir. Ayrıca,
MyViewModel
bağımlılığı nedeniyle MyDescendant
daha az yeniden kullanılabilir çünkü
Bunlar artık birbiriyle ilişkilendirildi. Şunlardan geçemeyen alternatifi düşünün:
alt türe bağımlılığı artırır ve kontrol ilkelerinin tersini kullanır.
üst öğeyi mantığı yürütmekten sorumlu hale getirir:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... ReusableLoadDataButton( onLoadClick = { myViewModel.loadData() } ) } @Composable fun ReusableLoadDataButton(onLoadClick: () -> Unit) { Button(onClick = onLoadClick) { Text("Load data") } }
Bu yaklaşım, farklı metodolojileri ve alt atalarından gelen çocuklardır. Üst composable'lar genellikle daha esnek alt düzey composable'lara olmaya başladı.
Benzer bir şekilde, @Composable
içerik lambda'ları
aynı avantajları sağlar:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... ReusablePartOfTheScreen( content = { Button( onClick = { myViewModel.loadData() } ) { Text("Confirm") } } ) } @Composable fun ReusablePartOfTheScreen(content: @Composable () -> Unit) { Column { // ... content() } }
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Compose'da bir temanın anatomisi
- Compose'da Görünümleri kullanma
- Jetpack Compose için Kotlin