Dikkat edilmesi gereken diğer noktalar

Görünümler'den Compose'a geçiş tamamen kullanıcı arayüzüyle ilgili olsa da birçok güvenli ve artımlı bir taşıma gerçekleştirmek için dikkate alınması gereken noktalar vardır. Bu taşıma işlemi sırasında göz önünde bulundurulması gereken bazı Compose'a görüntüleme tabanlı uygulama.

Uygulamanızın temasını taşıma

Android uygulamalarına tema eklemek için önerilen tasarım sistemi Materyal Tasarım'dır.

Görünüm tabanlı uygulamalarda, Materyal'in üç sürümü mevcuttur:

  • Materyal Tasarım 1, AppCompat kitaplığı (ör. Theme.AppCompat.*)
  • Materyal Tasarım 2, MDC-Android kütüphane (ör. Theme.MaterialComponents.*)
  • Materyal Tasarım 3, MDC-Android kütüphane (ör. Theme.Material3.*)

Oluşturma uygulamaları için Material'ın iki sürümü vardır:

  • Materyal Tasarım 2, Materyal Oluşturma kitaplığı (ör. androidx.compose.material.MaterialTheme)
  • Materyal Tasarım 3, Oluşturma Materyal 3 kitaplığı (ör. androidx.compose.material3.MaterialTheme)

Uygulamanızın tasarım sistemiyse en yeni sürümü (Material 3) kullanmanızı öneririz kişi bunu yapabilecek durumda olacaktır. Her iki Görünüm için de taşıma kılavuzları mevcut ve Oluştur:

Materyalin hangi sürümüne sahip olursa olsun Compose'da yeni ekran oluştururken Kullandığınız tasarımda, herhangi bir uygulamadan önce MaterialTheme uyguladığınızdan emin olun Compose Material kitaplıklarından kullanıcı arayüzü yayınlayan composable'lar. Materyal bileşenler (Button, Text vb.), mevcut bir MaterialTheme değerine bağlıdır ve bunlar olmadan davranışları tanımsızdır.

Tümü Jetpack Compose örnekleri MaterialTheme temel alınarak oluşturulmuş özel bir Oluştur teması kullanın.

Daha fazla bilgi edinmek için Compose'daki tasarım sistemleri ve XML temalarını Compose'a taşıma sayfalarına göz atın.

Uygulamanızda Navigasyon bileşenini kullanıyorsanız Oluşturma ile Gezinme - Birlikte Çalışabilirlik ve Daha fazla bilgi için Jetpack Gezinme'yi Gezinme Oluşturma'ya taşıyın.

Karma Oluşturma/Görünümler kullanıcı arayüzünüzü test etme

Uygulamanızın bazı bölümlerini Compose'a taşıdıktan sonra test, uygulamanızın hiçbir şeyi düzeltmediniz.

Bir etkinlik veya parça Oluşturma özelliğini kullandığında, createAndroidComposeRule ActivityScenarioRule tercih edebilirsiniz. createAndroidComposeRule entegrasyonu ActivityScenarioRule ve ComposeTestRule ile Oluşturma ve oluşturma işlemlerini test etmenize olanak tanır. Kodu aynı anda görüntüleyebilirsiniz.

class MyActivityTest {
    @Rule
    @JvmField
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test
    fun testGreeting() {
        val greeting = InstrumentationRegistry.getInstrumentation()
            .targetContext.resources.getString(R.string.greeting)

        composeTestRule.onNodeWithText(greeting).assertIsDisplayed()
    }
}

Test hakkında daha fazla bilgi edinmek için Oluşturma düzeninizi test etme konusuna bakın. Örneğin, Kullanıcı arayüzü test çerçeveleriyle birlikte çalışabilirlik hakkında daha fazla bilgi için bkz. Espresso ile birlikte çalışabilirlik ve UiAutomator ile birlikte çalışabilirlik.

Compose'u mevcut uygulama mimarinizle entegre etme

Tek Yönlü Veri Akışı (UDF) mimarisi desenleri de Compose ile uyumlu. Uygulama, (MVP) gibi mimari kalıplarına bağlı olarak değil, Compose'dan önce veya kullanım sırasında kullanıcı arayüzünün bu bölümünü UDF'ye taşıyın.

Compose'da ViewModel kullanma

Mimari Bileşenleri ViewModel kitaplığındaki Herhangi bir composable'dan ViewModel viewModel() fonksiyonuna ilişkin Oluşturma ve diğer kitaplıklar bölümünde açıklanmıştır.

Oluştur'u kullanırken aynı ViewModel türünün ViewModel öğeleri View yaşam döngüsü kapsamlarını izlediğinden farklı composable'lar kullanılabilir. İlgili içeriği oluşturmak için kullanılan kapsam, ana makine etkinliği, parça veya gezinme grafiği olur. Navigasyon kitaplığı kullanılır.

Örneğin, composable'lar bir etkinlik içinde barındırılıyorsa viewModel() her zaman yalnızca etkinlik tamamlandığında silinen aynı örneği döndürür. Aşağıdaki örnekte, aynı kullanıcı ("user1") iki kez selamlanmıştır çünkü aynı GreetingViewModel örneği yardımcı olur. Oluşturulan ilk ViewModel örnek, diğer composables.

class GreetingActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MaterialTheme {
                Column {
                    GreetingScreen("user1")
                    GreetingScreen("user2")
                }
            }
        }
    }
}

@Composable
fun GreetingScreen(
    userId: String,
    viewModel: GreetingViewModel = viewModel(  
        factory = GreetingViewModelFactory(userId)  
    )
) {
    val messageUser by viewModel.message.observeAsState("")
    Text(messageUser)
}

class GreetingViewModel(private val userId: String) : ViewModel() {
    private val _message = MutableLiveData("Hi $userId")
    val message: LiveData<String> = _message
}

class GreetingViewModelFactory(private val userId: String) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return GreetingViewModel(userId) as T
    }
}

Gezinme grafikleri olarak ViewModel öğelerinin kapsamı, bir gezinme grafiğindeki hedefte ViewModel öğesinin farklı bir örneği vardır. Bu durumda ViewModel, hedefin yaşam döngüsünü kapsar ve hedef geri yığından kaldırıldığında silinir. Aşağıdaki örnekte, kullanıcı Profil ekranına gittiğinde yeni bir GreetingViewModel örneği oluşturuldu.

@Composable
fun MyApp() {
    NavHost(rememberNavController(), startDestination = "profile/{userId}") {
        /* ... */
        composable("profile/{userId}") { backStackEntry ->
            GreetingScreen(backStackEntry.arguments?.getString("userId") ?: "")
        }
    }
}

Doğru bilgi kaynağı

Oluştur'u kullanıcı arayüzünün bir bölümünde kullandığınızda View sistem kodunun verileri paylaşması gerekir. Mümkünse bu paylaşılan durumu, UDF en iyi uygulamalarını izleyen başka bir sınıfa ekleyin. her iki platform tarafından kullanılan örneğin, ViewModel veri güncellemeleri ortaya çıkarmak için, paylaşılan verilerin üretilmesine neden olabilir.

Ancak, paylaşılacak veriler değişkense veya bir kullanıcı arayüzü öğesine sıkı sıkıya bağlı. Bu durumda bir sistem kabul etmesi ve bu sistemin, veri güncellemelerini diğer sistemle paylaşması gerekir. Kullanıcı genel kurala göre, doğru kaynağın, ilgili öğeye ait olması kullanıcı arayüzü hiyerarşisinin köküne daha yakındır.

Doğru bilgi kaynağı olarak yazın

Şunu kullanın: SideEffect composable'ı kullanarak Compose durumunu Compose dışı koda yayınlayabilirsiniz. Bu durumda, veri kaynağı, durum güncellemeleri gönderen bir composable'da tutulur.

Örneğin, analiz kitaplığınız kullanıcılarınızı segmentlere ayırmanıza özel meta veriler ekleyerek nüfusu (bu örnekte kullanıcı özellikleri) ve sonraki tüm Analytics etkinliklerine katkıda bulunur. Verinin kullanıcı türünü analiz kitaplığınıza eklemek için SideEffect değerini kullanın.

@Composable
fun rememberFirebaseAnalytics(user: User): FirebaseAnalytics {
    val analytics: FirebaseAnalytics = remember {
        FirebaseAnalytics()
    }

    // On every successful composition, update FirebaseAnalytics with
    // the userType from the current User, ensuring that future analytics
    // events have this metadata attached
    SideEffect {
        analytics.setUserProperty("userType", user.userType)
    }
    return analytics
}

Daha fazla bilgi için Compose'da yan etkiler bölümüne bakın.

Bilgi kaynağı olarak sistemi göster

Görüntüleme sistemi eyaletin sahibiyse ve Oluştur ile paylaşıyorsa şunu öneririz: durumu, iş parçacığı açısından güvenli hâle getirmek üzere mutableStateOf nesne içine sarmalarsınız. Oluştur'u tıklayın. Bu yaklaşımı kullanırsanız composable işlevler basitleştirilmiştir çünkü bu artık veri kaynağına sahip değiller, ancak Görünüm sisteminin durumu kullanan Görünümler de dahildir.

Aşağıdaki örnekte, CustomViewGroup bir TextView ve bir İçinde TextField composable bulunan ComposeView. TextView özelliğinin gösterilmesi gerekiyor Kullanıcının TextField içinde yazdığı içeriğin içeriği.

class CustomViewGroup @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : LinearLayout(context, attrs, defStyle) {

    // Source of truth in the View system as mutableStateOf
    // to make it thread-safe for Compose
    private var text by mutableStateOf("")

    private val textView: TextView

    init {
        orientation = VERTICAL

        textView = TextView(context)
        val composeView = ComposeView(context).apply {
            setContent {
                MaterialTheme {
                    TextField(value = text, onValueChange = { updateState(it) })
                }
            }
        }

        addView(textView)
        addView(composeView)
    }

    // Update both the source of truth and the TextView
    private fun updateState(newValue: String) {
        text = newValue
        textView.text = newValue
    }
}

Paylaşılan kullanıcı arayüzü taşınıyor

Kademeli olarak Compose'a geçiş yapıyorsanız paylaşılan kullanıcı arayüzünü kullanmanız gerekebilir öğelerini görüntüleme ve yönetme işlemlerini yapabilirsiniz. Örneğin, uygulamanızda özel CallToActionButton bileşenini, Oluşturduğunuz ve görüntülemeye dayalı ekranlar.

Compose'da paylaşılan kullanıcı arayüzü öğeleri, uygulamasında, XML kullanılarak stil verilen öğenin veya özel bir görünüm olmasından bağımsız olarak uygulanır. Örneğin, Örneğin, şuna özel çağrınız için bir CallToActionButton composable: işlem Button bileşeni.

Görünüme dayalı ekranlarda composable'ı kullanmak için, şu özelliklere sahip özel bir görünüm sarmalayıcı oluşturun: AbstractComposeView ile başlayıp uzanıyor. Geçersiz kılınmış Content composable'da, oluşturduğunuz composable'ı aşağıdaki örneğe bakın:

@Composable
fun CallToActionButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            containerColor = MaterialTheme.colorScheme.secondary
        ),
        onClick = onClick,
        modifier = modifier,
    ) {
        Text(text)
    }
}

class CallToActionViewButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : AbstractComposeView(context, attrs, defStyle) {

    var text by mutableStateOf("")
    var onClick by mutableStateOf({})

    @Composable
    override fun Content() {
        YourAppTheme {
            CallToActionButton(text, onClick)
        }
    }
}

Oluşturulabilir parametrelerin, özel görünüm. Bu da özel CallToActionViewButton görünümünü şişirebilir ve kullanılabilir hale getirir, geleneksel bir görünüm gibi. Görünüm Bağlama ile bunun bir örneğini görebilirsiniz aşağıda bulabilirsiniz:

class ViewBindingActivity : ComponentActivity() {

    private lateinit var binding: ActivityExampleBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityExampleBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.callToAction.apply {
            text = getString(R.string.greeting)
            onClick = { /* Do something */ }
        }
    }
}

Özel bileşen değişken durum içeriyorsa doğru.

Sunudan bölme durumuna öncelik ver

Geleneksel olarak View, durum bilgilidir. View, şu alanları yönetir: Ne gösterileceğini ve nasıl gösterileceğini açıklayın. Google Takvim widget'ını View öğesini Compose'a dönüştürüyorsanız oluşturulan verileri durum kaldırma bölümünde daha ayrıntılı olarak açıklandığı gibi tek yönlü bir veri akışı elde etmek.

Örneğin, bir View,visibility görünmez veya kaybolabilir. Bu, View öğesinin doğal bir özelliğidir. Bu sırada diğer kod parçaları View öğesinin görünürlüğünü değiştirebilir, yalnızca View ne olduğunu gerçekten biliyor. Bunu sağlamanın mantığı, bir View görünür olduğunda hataya açık olabilir ve genellikle View ile bağlantılıdır kendisi.

Buna karşın Compose, tamamen farklı composable'ları görüntülemeyi kolaylaştırır (kotlin'de koşullu mantığı kullanarak):

@Composable
fun MyComposable(showCautionIcon: Boolean) {
    if (showCautionIcon) {
        CautionIcon(/* ... */)
    }
}

CautionIcon web sitesinin tasarımı gereği, neden gösterildiğini bilmesine veya bununla ilgilenmesine gerek yoktur. visibility kavramı da yoktur. O ya bestededir, ya da değildir.

Durum yönetimi ile sunum mantığını net bir şekilde birbirinden ayırarak, durumu kullanıcı arayüzüne dönüştürme olarak görüntüleme şeklinizi özgürce değiştirebilirsiniz. Olmak composable'ı yeniden kullanılabilir hâle getirdiği için, eyalet sahipliği daha esnektir.

Kapsüllenmiş ve yeniden kullanılabilir bileşenleri tanıtın

View öğelerinin genellikle nerede bulunduklarına dair bir fikri vardır: Bir Activity içinde, Dialog, Fragment veya başka bir View hiyerarşisinin içinde başka bir yerde. Çünkü genellikle statik düzen dosyalarından şişirilirler. Bu dosya, bir View genelde çok katıdır. Bu, daha sıkı bağlantı sağlar ve bir View değerinin değiştirilmesi veya yeniden kullanılması daha zordur.

Örneğin, özel bir View belirli bir özelliğin alt görünümüne sahip olduğunu belirli bir kimlikle yazmanızı ve özelliklerini doğrudan eyleme dökülebilir. Bu işlem, söz konusu View öğelerini sıkı bir şekilde birleştirir: özel View çocuğu bulamazsa kilitlenebilir veya bozulabilir, çocuk da büyük olasılıkla bulamaz. özel View üst öğesi olmadan yeniden kullanılabilir.

Bu, yeniden kullanılabilir composable'larla Compose'da daha az sorun yaşanır. Ebeveynler şunları yapabilir: durumu ve geri çağırmaları kolayca belirtebilir, böylece yeniden kullanılabilir composable'lar yazabilirsiniz ve nerede kullanılacaklarını bilmek zorunda kalmadan.

@Composable
fun AScreen() {
    var isEnabled by rememberSaveable { mutableStateOf(false) }

    Column {
        ImageWithEnabledOverlay(isEnabled)
        ControlPanelWithToggle(
            isEnabled = isEnabled,
            onEnabledChanged = { isEnabled = it }
        )
    }
}

Yukarıdaki örnekte, üç parça da daha kapsüllenmiş ve daha az ilişkilidir:

  • ImageWithEnabledOverlay uygulamasının yalnızca geçerli isEnabled öğesinin ne olduğunu bilmesi gerekiyor belirtin. ControlPanelWithToggle varlığının bilmesi gerekmez veya nasıl kontrol edilebildiğini bile fark edebilirsiniz.

  • ControlPanelWithToggle, ImageWithEnabledOverlay adlı cihazın mevcut olduğunu bilmiyor. isEnabled, sıfır, bir veya daha fazla şekilde gösterilebilir ve ControlPanelWithToggle adlı kullanıcının değişmesi gerekmez.

  • Üst öğe için, ImageWithEnabledOverlay öğesinin ne kadar derinlemesine iç içe yerleştirilmiş olduğu önemli değildir veya ControlPanelWithToggle. Bu çocuklar, değişiklikler için animasyon başka çocuklara içerik aktarmaktan bahsedeceğiz.

Bu kalıp kontrolün ters çevirmesi olarak bilinir. Daha fazla bilgi edinmek için hakkındaki CompositionLocal belgeleri inceleyebilirsiniz.

Ekran boyutu değişikliklerini işleme

Farklı pencere boyutları için farklı kaynaklara sahip olmak, projenizin duyarlı View düzenleri oluşturabilirsiniz. Nitelikli kaynaklar bir seçenek olarak ekran düzeyinde düzenle ilgili kararlar almak için Compose'u kullanmak çok daha düzenlerini normal koşullu mantıkla tamamen kodda tutar. Daha fazla bilgi edinmek için Pencere boyutu sınıfları başlıklı makaleyi inceleyin.

Ayrıca, Farklı ekran boyutlarını destekleme başlıklı makaleyi inceleyin. Compose'un uyarlanabilir kullanıcı arayüzleri oluşturmak için sunduğu teknikleri öğrenin.

Görünümler ile iç içe geçmiş kaydırma

Sayfalar arasında iç içe kaydırmayı etkinleştirme hakkında daha fazla bilgi için kaydırılabilir görünüm öğeleri ve kaydırılabilir composable'lar, her iki yönde iç içe yerleştirilmiş. sesli oku İç içe kaydırma birlikte çalışabilirliği.

RecyclerView uygulamasında oluştur

RecyclerView içindeki derlenebilirler, RecyclerView sürümünden bu yana iyi performans gösteriyor 1.3.0-alpha02. Şu sürümün en az 1.3.0-alpha02 sürümünü kullandığınızdan emin olun: Bu avantajları görmek için RecyclerView.

WindowInsets, Görünümler ile birlikte çalışabilir

Ekranınızda hem Görünümler hem de görünümler olduğunda varsayılan değerleri geçersiz kılmanız gerekebilir. Kodu aynı hiyerarşide oluşturun. Bu durumda, konu hakkında ek öğeleri hangisinin tüketmesi gerektiği ve hangisinin yoksayılması gerektiği.

Örneğin, en dıştaki düzeniniz bir Android View düzeniyse insetleri Görüntüle sisteminde tüketme ve Oluşturma için bunları yoksayma. Alternatif olarak, en dıştaki düzeniniz bir composable ise inset'leri ekleyin ve AndroidView composable'ı buna uygun şekilde yerleştirin.

Varsayılan olarak her ComposeView, WindowInsetsCompat tüketim seviyesi. Bu varsayılan davranışı değiştirmek için ComposeView.consumeWindowInsets Hedef: false.

Daha fazla bilgi için E-posta Yazma'da WindowInsets dokümanlarını okuyun.

ziyaret edin.