Görünümler'den Oluştur'a geçiş tamamen kullanıcı arayüzüyle ilgili olsa da güvenli ve artımlı bir taşıma işlemi gerçekleştirmek için dikkate alınması gereken birçok nokta vardır. Bu sayfada, görüntülemeye dayalı uygulamanızı Compose'a taşırken dikkate almanız gereken bazı noktalar açıklanmaktadır.
Uygulamanızın temasını taşıma
Android uygulamalarında tema oluşturmak için önerilen tasarım sistemi Materyal Tasarım'dır.
Görüntü tabanlı uygulamalar için üç Material sürümü mevcuttur:
- AppCompat kitaplığını kullanan Material Design 1 (ör.
Theme.AppCompat.*
) - MDC-Android kitaplığını (ör.
Theme.MaterialComponents.*
) kullanan Material Design 2 - MDC-Android kitaplığını (ör.
Theme.Material3.*
) kullanan Material Design 3
Oluşturma uygulamaları için iki Material sürümü mevcuttur:
- Compose Material kitaplığını (ör.
androidx.compose.material.MaterialTheme
) kullanan Material Design 2 - Compose Material 3 kitaplığını (ör.
androidx.compose.material3.MaterialTheme
) kullanan Material Design 3
Uygulamanızın tasarım sistemi bunu yapabilecek durumdaysa en son sürümü (Material 3) kullanmanızı öneririz. Hem Görünümler hem de Oluştur için taşıma kılavuzları mevcuttur:
- Görünümlerde 1. Malzeme ile 2. Malzeme Arasında
- Görünümlerde 2. Malzeme ile 3. Malzeme Arasında
- Oluştur'da 2. Malzeme'den 3. Malzeme'ye
Compose'da yeni ekranlar oluştururken, hangi Material Design sürümünü kullandığınızdan bağımsız olarak Compose Material kitaplıklarından kullanıcı arayüzü yayınlayan tüm derlenebilir öğelerin önüne bir MaterialTheme
uyguladığınızdan emin olun. Materyal bileşenleri (Button
, Text
vb.), MaterialTheme
'nin mevcut olmasına bağlıdır ve bu bileşen olmadan davranışları tanımlanmaz.
Tüm Jetpack Compose örnekleri, MaterialTheme
üzerine inşa edilmiş özel bir Compose teması kullanır.
Daha fazla bilgi edinmek için Oluştur'da tasarım sistemleri ve XML temalarını Oluştur'a taşıma başlıklı makaleleri inceleyin.
Navigasyon
Uygulamanızda Gezinme bileşenini kullanıyorsanız daha fazla bilgi için Compose ile gezinme - birlikte çalışabilirlik ve Jetpack Gezinme'yi Gezinme Compose'a taşıma başlıklı makalelere göz atın.
Karma Oluştur/Görüntülemeler kullanıcı arayüzünüzü test etme
Uygulamanızın bazı bölümlerini Compose'a taşıdıktan sonra, herhangi bir sorun yaşamadığınızdan emin olmak için test yapmanız önemlidir.
Bir etkinlik veya parçada Oluştur kullanılıyorsa ActivityScenarioRule
yerine createAndroidComposeRule
kullanmanız gerekir. createAndroidComposeRule
, kod oluşturma ve kod görüntüleme işlemlerini aynı anda test etmenizi sağlayan bir ComposeTestRule
ile ActivityScenarioRule
'i entegre eder.
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 başlıklı makaleyi inceleyin. Kullanıcı arayüzü test çerçeveleriyle birlikte çalışabilirlik için Espresso ile birlikte çalışabilirlik ve UiAutomator ile birlikte çalışabilirlik başlıklı makalelere bakın.
Compose'u mevcut uygulama mimarinizle entegre etme
Tek Yönlü Veri Akışı (UDF) mimari kalıpları, Compose ile sorunsuz bir şekilde çalışır. Uygulamada bunun yerine Model View Presenter (MVP) gibi başka mimari kalıpları kullanılıyorsa Compose'u kullanmaya başlamadan önce veya bu işlemi yaparken kullanıcı arayüzünün bu bölümünü UDF'ye taşımanızı öneririz.
Oluşturma'da ViewModel
kullanma
Mimari BileşenleriViewModel
kitaplığını kullanıyorsanız Kompozisyon ve diğer kitaplıklar bölümünde açıklandığı gibi viewModel()
işlevini çağırarak herhangi bir kompozisyondan ViewModel
'e erişebilirsiniz.
ViewModel
öğeleri Görünüm yaşam döngüsü kapsamlarını takip ettiğinden, Compose'u kullanırken farklı derlenebilir öğelerde aynı ViewModel
türünü kullanmaya dikkat edin. Kapsam, ana makine etkinliği, parça veya Gezinme kitaplığı kullanılıyorsa gezinme grafiği olacaktır.
Örneğin, derlenebilirler bir etkinlikte barındırılıyorsa viewModel()
her zaman aynı örneği döndürür ve bu örnek yalnızca etkinlik sona erdiğinde temizlenir.
Aşağıdaki örnekte, aynı GreetingViewModel
örneği ana makine etkinliği kapsamındaki tüm derlenebilir öğelerde yeniden kullanıldığı için aynı kullanıcı ("kullanıcı1") iki kez karşılanır. Oluşturulan ilk ViewModel
örneği, diğer birleştirilebilir öğelerde yeniden kullanılır.
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 } }
Navigasyon grafikleri ViewModel
öğelerini de kapsama aldığından, bir navigasyon grafiğinde hedef olan derlenebilir öğeler ViewModel
öğesinin farklı bir örneğine sahiptir.
Bu durumda ViewModel
, hedefin yaşam döngüsü kapsamına alınır ve hedef arka yığıntan kaldırıldığında temizlenir. Aşağıdaki örnekte, kullanıcı Profil ekranına gittiğinde yeni bir GreetingViewModel
örneği oluşturulur.
@Composable fun MyApp() { NavHost(rememberNavController(), startDestination = "profile/{userId}") { /* ... */ composable("profile/{userId}") { backStackEntry -> GreetingScreen(backStackEntry.arguments?.getString("userId") ?: "") } } }
Doğruluk kaynağı durumu
Kullanıcı arayüzünün bir bölümünde Oluştur'u kullandığınızda Oluştur ve Görüntüleme sistem kodunun veri paylaşması gerekebilir. Mümkün olduğunda bu paylaşılan durumu, her iki platform tarafından kullanılan UDF en iyi uygulamalarına uyan başka bir sınıfta kapsayabilirsiniz. Örneğin, veri güncellemelerini yayınlamak için paylaşılan verilerin akışını gösteren bir ViewModel
sınıfında.
Ancak paylaşılacak veriler değişkense veya bir kullanıcı arayüzü öğesine sıkıca bağlıysa bu her zaman mümkün olmayabilir. Bu durumda, bir sistem doğruluk kaynağı olmalı ve bu sistemin diğer sistemle veri güncellemelerini paylaşması gerekir. Genel kural olarak, doğruluk kaynağının sahibi kullanıcı arayüzü hiyerarşisinin köküne daha yakın olan öğe olmalıdır.
Doğru kaynak olarak oluşturma
Oluşturma durumunu Oluşturma dışı koda yayınlamak için SideEffect
kodlanabilir öğeyi kullanın. Bu durumda, doğruluk kaynağı, durum güncellemeleri gönderen bir bileşende tutulur.
Örneğin, analiz kitaplığınız, sonraki tüm analiz etkinliklerine özel meta veriler (bu örnekte kullanıcı özellikleri) ekleyerek kullanıcı kitlenizi segmentlere ayırmanıza olanak tanıyabilir. Mevcut kullanıcının kullanıcı türünü analiz kitaplığınıza iletmek için değerini güncellemek üzere SideEffect
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 Oluşturma'daki yan etkiler başlıklı makaleyi inceleyin.
Sistemi doğruluk kaynağı olarak görüntüleme
Görüntüleme sistemi durumun sahibiyse ve durumu Compose ile paylaşıyorsa durumu Compose için iş parçacığı açısından güvenli hale getirmek üzere mutableStateOf
nesnelerine sarmalamanızı öneririz. Bu yaklaşımı kullanırsanız artık doğruluk kaynağına sahip olmadıkları için birleştirilebilir işlevler basitleştirilir ancak Görüntü sisteminin, değişken durumu ve bu durumu kullanan Görüntüleri güncellemesi gerekir.
Aşağıdaki örnekte, bir CustomViewGroup
içinde bir TextView
ve TextField
bileşeni içeren bir ComposeView
yer almaktadır. TextView
, kullanıcının TextField
alanına yazdığı içeriği göstermelidir.
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ünü taşıma
Oluştur'a kademeli olarak geçiş yapıyorsanız hem Oluştur hem de Görüntüleme sisteminde ortak kullanıcı arayüzü öğelerini kullanmanız gerekebilir. Örneğin, uygulamanızda özel bir CallToActionButton
bileşeni varsa bunu hem Oluşturma hem de Görüntüleme tabanlı ekranlarda kullanmanız gerekebilir.
Oluşturma'da, paylaşılan kullanıcı arayüzü öğeleri, XML kullanılarak stilize edilmiş veya özel görünümlü olup olmadığına bakılmaksızın uygulama genelinde yeniden kullanılabilen bileşenler haline gelir. Örneğin, özel harekete geçirici mesaj Button
bileşeniniz için bir CallToActionButton
bileşeni oluşturursunuz.
Kompozitleri görünüme dayalı ekranlarda kullanmak için AbstractComposeView
'ten başlayan özel bir görünüm sarmalayıcısı oluşturun. Üzerine yazılmış Content
bileşenine, oluşturduğunuz bileşeni aşağıdaki örnekte gösterildiği gibi Oluşturma temanıza sarmalanmış olarak yerleştirin:
@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) } } }
Birleştirilebilir parametrelerin, özel görünüm içinde değiştirilebilir değişkenler haline geldiğine dikkat edin. Bu sayede özel CallToActionViewButton
görünümü, geleneksel bir görünüm gibi şişirilebilir ve kullanılabilir hale gelir. Aşağıda, Görüntü Bağlantısı ile ilgili bir örneğe bakın:
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şende değişken durum varsa Doğruluk durumu kaynağı bölümüne bakın.
Sunudan bölme durumuna öncelik verme
Geleneksel olarak View
durum bilgisine sahiptir. View
, nasıl gösterileceğinin yanı sıra nelerin gösterileceğini açıklayan alanları yönetir. Bir View
öğesini Compose'a dönüştürdüğünüzde, durum kaldırma bölümünde daha ayrıntılı olarak açıklandığı gibi tek yönlü bir veri akışı elde etmek için oluşturulan verileri ayırın.
Örneğin, bir View
öğesinin görünür, görünmez veya kaldırılmış olup olmadığını belirten bir visibility
özelliği vardır. Bu, View
'ün doğal bir özelliğidir. Diğer kod parçaları bir View
öğesinin görünürlüğünü değiştirebilir ancak mevcut görünürlüğünü gerçekten bilen tek öğe View
'dir. Bir View
öğesinin görünür olmasını sağlama mantığı hatalara açık olabilir ve genellikle View
öğesine bağlıdır.
Buna karşılık Compose, Kotlin'de koşullu mantık kullanarak tamamen farklı kompozisyonlar göstermeyi kolaylaştırır:
@Composable fun MyComposable(showCautionIcon: Boolean) { if (showCautionIcon) { CautionIcon(/* ... */) } }
Tasarım gereği, CautionIcon
'ün neden gösterildiğini bilmesi veya dikkate alması gerekmez ve visibility
kavramı yoktur: Kompozisyon'da ya vardır ya da yoktur.
Durum yönetimini ve sunum mantığını net bir şekilde ayırarak, durumu kullanıcı arayüzüne dönüştürme işlemi olarak içeriği nasıl görüntülediğinizi daha özgürce değiştirebilirsiniz. Gerekirse durumu kaldırmak, durum sahipliği daha esnek olduğundan birleştirilebilir öğeleri daha yeniden kullanılabilir hale getirir.
Kapsüllenmiş ve yeniden kullanılabilir bileşenleri tanıtma
View
öğeleri genellikle nerede bulundukları hakkında bir fikre sahiptir: Activity
, Dialog
, Fragment
veya başka bir View
hiyerarşisinin içinde bir yerde. Genellikle statik düzen dosyalarından şişirildiği için View
'lerin genel yapısı çok katı olma eğilimindedir. Bu durum, daha sıkı bir bağlantıya neden olur ve View
'ün değiştirilmesini veya yeniden kullanılmasını zorlaştırır.
Örneğin, özel bir View
, belirli bir kimliğe sahip belirli bir türde bir alt görünüme sahip olduğunu varsayabilir ve özelliklerini doğrudan bir işleme yanıt olarak değiştirebilir. Bu, söz konusu View
öğelerini birbirine sıkıca bağlar: Özel View
, alt öğeyi bulamadığı takdirde kilitlenebilir veya bozulabilir. Alt öğe de özel View
üst öğesi olmadan büyük olasılıkla yeniden kullanılamaz.
Bu, yeniden kullanılabilir bileşenlerle Oluştur'da daha az sorun teşkil eder. Ebeveynler durumu ve geri çağırma işlevlerini kolayca belirtebilir. Böylece, kullanılacakları yeri tam olarak bilmek zorunda kalmadan yeniden kullanılabilir bileşenler yazabilirsiniz.
@Composable fun AScreen() { var isEnabled by rememberSaveable { mutableStateOf(false) } Column { ImageWithEnabledOverlay(isEnabled) ControlPanelWithToggle( isEnabled = isEnabled, onEnabledChanged = { isEnabled = it } ) } }
Yukarıdaki örnekte, üç parçanın da kapsüllemesi daha fazla ve bağlantısı daha azdır:
ImageWithEnabledOverlay
'nin yalnızca mevcutisEnabled
durumunu bilmesi gerekir.ControlPanelWithToggle
'nin var olduğunu veya nasıl kontrol edilebileceğini bilmesi gerekmez.ControlPanelWithToggle
,ImageWithEnabledOverlay
'un varlığını bilmiyor.isEnabled
'ün sıfır, bir veya daha fazla şekilde gösterilmesi mümkündür veControlPanelWithToggle
'ün değişmesi gerekmez.Üst öğe için
ImageWithEnabledOverlay
veyaControlPanelWithToggle
'ün ne kadar derin iç içe yerleştirildiği önemli değildir. Bu çocuklar, değişiklikleri animasyonlu olarak gösterebilir, içerik değiştirebilir veya içerikleri diğer çocuklara aktarabilir.
Bu kalıp, kontrolün tersine çevrilmesi olarak bilinir. Bu konuda daha fazla bilgiyi CompositionLocal
dokümanlarında bulabilirsiniz.
Ekran boyutu değişikliklerini işleme
Farklı pencere boyutları için farklı kaynaklara sahip olmak, duyarlı View
düzenler oluşturmanın başlıca yollarından biridir. Uygun kaynaklar, ekran düzeyinde düzen kararları için hâlâ bir seçenek olsa da Compose, normal koşullu mantıkla düzenleri tamamen kodda değiştirmeyi çok daha kolay hale getirir. Daha fazla bilgi için Pencere boyutu sınıflarını kullanma başlıklı makaleyi inceleyin.
Ayrıca, Compose'un uyarlanabilir kullanıcı arayüzleri oluşturmak için sunduğu teknikler hakkında bilgi edinmek üzere Farklı ekran boyutlarını destekleme başlıklı makaleyi inceleyin.
Görünümlerle iç içe kaydırma
Her iki yönde de iç içe yerleştirilmiş, kaydırılabilir Görünüm öğeleri ile kaydırılabilir bileşenler arasında iç içe kaydırma birlikte çalışabilirliğini etkinleştirme hakkında daha fazla bilgi için İç içe kaydırma birlikte çalışabilirliği başlıklı makaleyi inceleyin.
RecyclerView
uygulamasında oluşturma
RecyclerView
'teki Composables, RecyclerView
1.3.0-alpha02 sürümünden beri performanslıdır. Bu avantajlardan yararlanmak için RecyclerView
'ın en az 1.3.0-alpha02 sürümünü kullandığınızdan emin olun.
WindowInsets
Görünümlerle birlikte çalışabilirlik
Ekranınızda aynı hiyerarşide hem Görünümler hem de Oluştur kodu varsa varsayılan iç içe eklemeleri geçersiz kılmanız gerekebilir. Bu durumda, hangi öğenin içe yerleştirilenleri kullanması ve hangi öğenin bunları yoksaması gerektiğini açıkça belirtmeniz gerekir.
Örneğin, en dıştaki düzeniniz bir Android View düzeniyse View sisteminde içe yerleştirilen öğeleri kullanmanız ve Oluştur için bunları yok saymanız gerekir.
Alternatif olarak, en dıştaki düzeniniz bir bileşense Oluştur'da iç içe eklemeleri kullanmanız ve AndroidView
bileşenlerini uygun şekilde doldurmanız gerekir.
Varsayılan olarak her ComposeView
, tüm iç metinleri WindowInsetsCompat
tüketim düzeyinde tüketir. Bu varsayılan davranışı değiştirmek için ComposeView.consumeWindowInsets
değerini false
olarak ayarlayın.
Daha fazla bilgi için Oluşturma'daki WindowInsets
dokümanlarını okuyun.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Emoji gösterme
- Oluşturma bölümündeki Material Design 2
- Oluştur'daki pencere iç içe eklemeleri