1. Giriş
Bu codelab'de telefonlar, tabletler ve katlanabilir cihazlar için uyarlanabilir uygulamalar oluşturmayı ve bu uygulamaların Jetpack Compose ile erişilebilirliği nasıl artırdığını öğreneceksiniz. Ayrıca Material 3 bileşenlerini ve temalandırmayı kullanmayla ilgili en iyi uygulamaları da öğreneceksiniz.
Konuya geçmeden önce uyarlanabilirlik ile neyi kastettiğimizi anlamanız önemlidir.
Uyum yeteneği
Uygulamanızın kullanıcı arayüzü, farklı pencere boyutlarını, yönlerini ve form faktörlerini hesaba katacak şekilde duyarlı olmalıdır. Uyarlanabilir düzen, kendisine sunulan ekran alanına göre değişir. Bu değişiklikler, alanı doldurmak için basit düzen ayarlamaları yapmaktan, ilgili gezinme stillerini seçmeye ve ek alan kullanmak için düzenleri tamamen değiştirmeye kadar çeşitlilik gösterir.
Daha fazla bilgi için Uyarlanabilir tasarım başlıklı makaleyi inceleyin.
Bu codelab'de, Jetpack Compose kullanırken uyarlanabilirliği nasıl kullanacağınızı ve bu konuda nasıl düşüneceğinizi öğreneceksiniz. Reply adlı bir uygulama geliştiriyorsunuz. Bu uygulama, her tür ekranda uyarlanabilirliği nasıl uygulayacağınızı ve uyarlanabilirlik ile erişilebilirliğin, kullanıcılara optimum deneyimi sunmak için nasıl birlikte çalıştığını gösteriyor.
Neler öğreneceksiniz?
- Uygulamanızı Jetpack Compose ile tüm pencere boyutlarını hedefleyecek şekilde tasarlama
- Uygulamanızı farklı katlanabilir cihazlara nasıl hedefleyeceğinizi öğrenin.
- Daha iyi erişilebilirlik için farklı gezinme türlerini kullanma
- Her pencere boyutu için en iyi deneyimi sağlamak üzere Material 3 bileşenlerini kullanma.
İhtiyacınız olanlar
- Android Studio'nun en son kararlı sürümü.
- Yeniden boyutlandırılabilir bir Android 13 sanal cihazı.
- Kotlin bilgisi
- Compose'un temel özelliklerini (ör.
@Composableek açıklaması) anlama - Compose düzenleri (ör.
RowveColumn) hakkında temel düzeyde bilgi sahibi olma. - Değiştiriciler (ör.
Modifier.padding()) hakkında temel bilgi sahibi olmanız gerekir.
Bu codelab'de, farklı cihaz türleri ve pencere boyutları arasında geçiş yapmanıza olanak tanıyan yeniden boyutlandırılabilir emülatörü kullanacaksınız.

Compose'a aşina değilseniz bu codelab'i tamamlamadan önce Jetpack Compose'un temelleri codelab'ini inceleyebilirsiniz.
Ne oluşturacaksınız?
- Uyarlanabilir tasarımlar, farklı Materyal gezinme seçenekleri ve optimum ekran alanı kullanımı için en iyi uygulamaları kullanan, Reply adlı etkileşimli bir e-posta istemcisi uygulaması.

2. Hazırlanın
Bu codelab'in kodunu almak için komut satırından GitHub deposunu klonlayın:
git clone https://github.com/android/codelab-android-compose.git cd codelab-android-compose/AdaptiveUiCodelab
Alternatif olarak, depoyu ZIP dosyası olarak indirebilirsiniz:
Ana daldaki kodla başlamanızı ve codelab'i kendi hızınızda adım adım uygulamanızı öneririz.
Projeyi Android Studio'da açın.
- Welcome to Android Studio (Android Studio'ya Hoş Geldiniz) penceresinde
Open an Existing Project'i (Mevcut Bir Projeyi Aç) seçin. - Klasörü seçin
<Download Location>/AdaptiveUiCodelab(build.gradleiçerenAdaptiveUiCodelabdizinini seçtiğinizden emin olun). - Android Studio projeyi içe aktardıktan sonra
maindalını çalıştırabildiğinizi test edin.
Başlangıç kodunu keşfetme
main dalı kodu, ui paketini içerir. Bu pakette aşağıdaki dosyalarla çalışacaksınız:
MainActivity.kt: Uygulamanızı başlattığınız giriş noktası etkinliği.ReplyApp.kt: Ana ekranın kullanıcı arayüzü composable'larını içerir.ReplyHomeViewModel.kt: Uygulama içeriği için verileri ve kullanıcı arayüzü durumunu sağlar.ReplyListContent.kt: Listeler ve ayrıntı ekranları sağlamak için composable'ları içerir.
Bu uygulamayı yeniden boyutlandırılabilir bir emülatörde çalıştırıp telefon veya tablet gibi farklı cihaz türlerini denerseniz kullanıcı arayüzü, ekran alanından yararlanmak veya erişilebilirlik ergonomisi sağlamak yerine yalnızca verilen alana genişler.


Ekran alanından yararlanmak, kullanılabilirliği artırmak ve genel kullanıcı deneyimini iyileştirmek için güncelleyeceksiniz.
3. Uygulamaları uyarlanabilir hale getirme
Bu bölümde, uygulamaları uyarlanabilir hale getirmenin ne anlama geldiği ve Material 3'ün bu süreci kolaylaştırmak için hangi bileşenleri sağladığı açıklanmaktadır. Ayrıca telefonlar, tabletler, büyük tabletler ve katlanabilir cihazlar da dahil olmak üzere hedefleyeceğiniz ekran türlerini ve durumlarını kapsar.
Öncelikle pencere boyutları, katlama pozisyonları ve farklı gezinme seçeneklerinin temellerini öğreneceksiniz. Ardından, uygulamanızı daha uyarlanabilir hale getirmek için bu API'leri kullanabilirsiniz.
Pencere boyutları
Android cihazlar; telefonlar, katlanabilir cihazlar, tabletler ve ChromeOS cihazlar gibi çeşitli şekil ve boyutlarda sunulur. Mümkün olduğunca çok pencere boyutunu desteklemek için kullanıcı arayüzünüzün duyarlı ve uyarlanabilir olması gerekir. Uygulamanızın kullanıcı arayüzünü değiştireceğiniz doğru eşiği bulmanıza yardımcı olmak için cihazları önceden tanımlanmış boyut sınıflarına (kompakt, orta ve genişletilmiş) ayırmaya yardımcı olan kesme noktası değerlerini tanımladık. Bu değerlere pencere boyutu sınıfları adı verilir. Bunlar, duyarlı ve uyarlanabilir uygulama düzenleri tasarlamanıza, geliştirmenize ve test etmenize yardımcı olan, belirli bir görüşe dayalı bir dizi görünüm alanı kesme noktasıdır.
Kategoriler, düzenin basitliği ile uygulamanızı benzersiz kullanım alanlarına göre optimize etme esnekliği arasında denge kurmak için özel olarak seçilmiştir. Pencere boyutu sınıfı her zaman uygulamaya sunulan ekran alanına göre belirlenir. Bu alan, çoklu görev veya diğer segmentasyonlar için fiziksel ekranın tamamı olmayabilir.


Hem genişlik hem de yükseklik ayrı ayrı sınıflandırılır. Bu nedenle, uygulamanızın herhangi bir zamanda iki pencere boyutu sınıfı vardır: biri genişlik, diğeri yükseklik için. Dikey kaydırmanın yaygınlığı nedeniyle kullanılabilir genişlik genellikle kullanılabilir yükseklikten daha önemlidir. Bu nedenle, bu durumda genişlik boyutu sınıflarını da kullanacaksınız.
Katlama durumları
Katlanabilir cihazlar, farklı boyutları ve menteşeleri nedeniyle uygulamanızın uyum sağlayabileceği daha fazla durum sunar. Menteşeler, ekranın bir kısmını kapatarak bu alanı içerik göstermeye uygun hale getirebilir. Ayrıca menteşeler, cihaz açıldığında iki ayrı fiziksel ekran olduğu anlamına gelecek şekilde ayrılabilir.

Ayrıca, kullanıcı menteşe kısmen açıkken iç ekrana bakıyor olabilir. Bu durumda, katlama yönüne bağlı olarak farklı fiziksel duruşlar ortaya çıkar: masaüstü duruşu (yatay katlama, yukarıdaki resimde sağda gösterilmiştir) ve kitap duruşu (dikey katlama).
Katlama pozisyonları ve menteşeler hakkında daha fazla bilgi edinin.
Bunların tümü, katlanabilir cihazları destekleyen uyarlanabilir düzenler uygularken dikkate alınması gereken noktalardır.
Uyarlanabilir bilgiler alma
Material3 adaptive kitaplığı, uygulamanızın çalıştığı pencereyle ilgili bilgilere kolayca erişmenizi sağlar.
- Bu yapıt ve sürümü için sürüm kataloğu dosyasına girişler ekleyin:
gradle/libs.versions.toml
[versions]
material3Adaptive = "1.0.0"
[libraries]
androidx-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3Adaptive" }
- Uygulama modülünün derleme dosyasına yeni kitaplık bağımlılığını ekleyin ve ardından Gradle senkronizasyonu gerçekleştirin:
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive)
}
Artık herhangi bir composable kapsamda, mevcut pencere boyutu sınıfı ve cihazın masaüstü gibi katlanabilir bir duruşta olup olmadığı gibi bilgileri içeren bir WindowAdaptiveInfo nesnesi almak için currentWindowAdaptiveInfo() kullanabilirsiniz.
Bu özelliği MainActivity'da hemen deneyebilirsiniz.
onCreate()ReplyThemebloğunun içinde, pencereye uyarlanabilir bilgileri alın ve boyut sınıflarınıTextcomposable'ında gösterin. BunuReplyApp()öğesinden sonra ekleyebilirsiniz:
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ReplyTheme {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
ReplyApp(
replyHomeUIState = uiState,
onEmailClick = viewModel::setSelectedEmail
)
val adaptiveInfo = currentWindowAdaptiveInfo()
val sizeClassText =
"${adaptiveInfo.windowSizeClass.windowWidthSizeClass}\n" +
"${adaptiveInfo.windowSizeClass.windowHeightSizeClass}"
Text(
text = sizeClassText,
color = Color.Magenta,
modifier = Modifier.padding(
WindowInsets.safeDrawing.asPaddingValues()
)
)
}
}
}
Uygulamayı şimdi çalıştırdığınızda, uygulama içeriğinin üzerine pencere boyutu sınıfları yazdırılır. Pencereye uyarlanabilir bilgilerde başka neler sunulduğunu inceleyebilirsiniz. Ardından, uygulama içeriğini kapsadığı ve sonraki adımlar için gerekli olmayacağı için bu Text öğesini kaldırabilirsiniz.
4. Dinamik gezinme
Şimdi uygulamanızın daha kolay kullanılabilmesi için cihaz durumu ve boyutu değiştikçe uygulamanın gezinme özelliğini uyarlayacaksınız.
Kullanıcılar telefonu tutarken parmakları genellikle ekranın alt kısmında olur. Kullanıcılar açık bir katlanabilir cihazı veya tableti tutarken parmakları genellikle kenarlara yakın olur. Kullanıcılarınız, ellerini aşırı derecede hareket ettirmeleri veya yerlerini değiştirmeleri gerekmeden bir uygulamada gezinebilmeli ya da uygulamayla etkileşim başlatabilmelidir.
Uygulamanızı tasarlarken ve etkileşimli kullanıcı arayüzü öğelerini düzeninizde nereye yerleştireceğinize karar verirken ekranın farklı bölgelerinin ergonomik etkilerini göz önünde bulundurun.
- Cihazı tutarken hangi alanlara rahatça ulaşabiliyorsunuz?
- Hangi alanlara yalnızca parmaklar uzatılarak erişilebilir? Bu durum rahatsız edici olabilir.
- Hangi alanlara ulaşmak zordur veya kullanıcı cihazı nerede tutuyorsa oradan çok uzaktadır?
Kullanıcıların etkileşime girdiği ilk şey gezinmedir. Gezinme, kritik kullanıcı yolculuklarıyla ilgili yüksek öneme sahip işlemleri içerdiğinden en kolay ulaşılabilen alanlara yerleştirilmelidir. Material uyarlanabilir kitaplığı, cihazın pencere boyutu sınıfına bağlı olarak gezinmeyi uygulamanıza yardımcı olan çeşitli bileşenler sunar.
Alt gezinme
Alt gezinme, kompakt boyutlar için idealdir. Çünkü cihazı doğal olarak başparmağımızın alt gezinme dokunma noktalarına kolayca ulaşabileceği şekilde tutarız. Kompakt bir cihazınız veya kompakt katlanmış durumda bir katlanabilir cihazınız olduğunda bu özelliği kullanın.

Gezinme sütunu
Orta genişlikteki pencere boyutunda, başparmağımız doğal olarak cihazın yan tarafına denk geldiğinden gezinme çubuğu erişilebilirlik için idealdir. Daha fazla bilgi göstermek için gezinme çubuğunu gezinme çekmecesiyle de birleştirebilirsiniz.

Gezinme çekmecesi
Gezinme çekmecesi, gezinme sekmeleriyle ilgili ayrıntılı bilgileri görmenin kolay bir yolunu sunar ve tablet veya daha büyük cihazlar kullanırken kolayca erişilebilir. İki tür gezinme çekmecesi vardır: modal gezinme çekmecesi ve kalıcı gezinme çekmecesi.
Modal gezinme çekmecesi
İçeriğin üzerinde kaplama olarak genişletilebildiği veya gizlenebildiği için kompakt ve orta boyutlu telefonlar ile tabletlerde modal gezinme çekmecesini kullanabilirsiniz. Bu bazen gezinme çubuğuyla birleştirilebilir.

Kalıcı gezinme çekmecesi
Büyük tabletlerde, Chromebook'larda ve masaüstü bilgisayarlarda sabit gezinme için kalıcı bir gezinme çekmecesi kullanabilirsiniz.

Dinamik gezinmeyi uygulama
Şimdi, cihazın durumu ve boyutu değiştikçe farklı gezinme türleri arasında geçiş yapacaksınız.
Şu anda uygulama, cihazın durumundan bağımsız olarak ekran içeriğinin altında her zaman bir NavigationBar gösteriyor. Bunun yerine, geçerli pencere boyutu sınıfı gibi bilgilere göre farklı gezinme bileşenleri arasında otomatik olarak geçiş yapmak için Material NavigationSuiteScaffold bileşenini kullanabilirsiniz.
- Sürüm kataloğunu ve uygulamanın derleme komut dosyasını güncelleyerek bu bileşeni almak için Gradle bağımlılığını ekleyin, ardından Gradle senkronizasyonu gerçekleştirin:
gradle/libs.versions.toml
[versions]
material3AdaptiveNavSuite = "1.3.0"
[libraries]
androidx-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3AdaptiveNavSuite" }
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive.navigation.suite)
}
ReplyApp.ktiçindeReplyNavigationWrapper()composable işlevini bulun veColumnile içeriğiniNavigationSuiteScaffoldile değiştirin:
ReplyApp.kt
@Composable
private fun ReplyNavigationWrapperUI(
content: @Composable () -> Unit = {}
) {
var selectedDestination: ReplyDestination by remember {
mutableStateOf(ReplyDestination.Inbox)
}
NavigationSuiteScaffold(
navigationSuiteItems = {
ReplyDestination.entries.forEach {
item(
selected = it == selectedDestination,
onClick = { /*TODO update selection*/ },
icon = {
Icon(
imageVector = it.icon,
contentDescription = stringResource(it.labelRes)
)
},
label = {
Text(text = stringResource(it.labelRes))
},
)
}
}
) {
content()
}
}
navigationSuiteItems bağımsız değişkeni, item() işlevini kullanarak öğe eklemenize olanak tanıyan bir bloktur. Bu, LazyColumn içinde öğe eklemeye benzer. Bu kod, sondaki lambda'nın içinde ReplyNavigationWrapperUI()'ye bağımsız değişken olarak iletilen content() işlevini çağırır.
Uygulamayı emülatörde çalıştırın ve boyutları telefon, katlanabilir cihaz ve tablet arasında değiştirmeyi deneyin. Gezinme çubuğunun gezinme rayına ve tekrar gezinme çubuğuna dönüştüğünü göreceksiniz.
Yatay modda tablet gibi çok geniş pencerelerde kalıcı gezinme çekmecesini göstermek isteyebilirsiniz. NavigationSuiteScaffold, kalıcı bir çekmecenin gösterilmesini destekler ancak bu özellik mevcut WindowWidthSizeClass değerlerinin hiçbirinde gösterilmez. Ancak küçük bir değişiklikle bunu sağlayabilirsiniz.
- Aşağıdaki kodu
NavigationSuiteScaffoldçağrısından hemen önce ekleyin:
ReplyApp.kt
@Composable
private fun ReplyNavigationWrapperUI(
content: @Composable () -> Unit = {}
) {
var selectedDestination: ReplyDestination by remember {
mutableStateOf(ReplyDestination.Inbox)
}
val windowSize = with(LocalDensity.current) {
currentWindowSize().toSize().toDpSize()
}
val layoutType = if (windowSize.width >= 1200.dp) {
NavigationSuiteType.NavigationDrawer
} else {
NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(
currentWindowAdaptiveInfo()
)
}
NavigationSuiteScaffold(
layoutType = layoutType,
...
) {
content()
}
}
Bu kod önce pencere boyutunu alır ve currentWindowSize() ile LocalDensity.current kullanarak DP birimlerine dönüştürür. Ardından, gezinme kullanıcı arayüzünün düzen türüne karar vermek için pencere genişliğini karşılaştırır. Pencere genişliği en az 1200.dp ise NavigationSuiteType.NavigationDrawer kullanılır. Aksi takdirde varsayılan hesaplamaya geri dönülür.
Uygulamayı yeniden yeniden boyutlandırılabilir emülatörünüzde çalıştırıp farklı türleri denediğinizde, ekran yapılandırması her değiştiğinde veya katlanabilir bir cihazı açtığınızda gezinmenin bu boyuta uygun türe değiştiğini fark edeceksiniz.

Tebrikler! Farklı pencere boyutlarını ve durumlarını desteklemek için farklı gezinme türleri hakkında bilgi edindiniz.
Sonraki bölümde, aynı liste öğesini uçtan uca uzatmak yerine kalan ekran alanından nasıl yararlanabileceğinizi öğreneceksiniz.
5. Ekran alanı kullanımı
Uygulamayı küçük bir tablette, katlanmamış bir cihazda veya büyük bir tablette çalıştırıyor olmanız fark etmeksizin ekran, kalan alanı dolduracak şekilde genişletilir. Bu ekran alanından yararlanarak daha fazla bilgi göstermek istiyorsunuz. Örneğin, bu uygulamada e-posta ve ileti dizilerini aynı sayfada gösteriyorsunuz.
Material 3, her biri kompakt, orta ve genişletilmiş pencere boyutu sınıfları için yapılandırmalara sahip üç standart düzen tanımlar. Liste Ayrıntısı standart düzeni bu kullanım alanı için mükemmeldir ve oluşturma bölümünde ListDetailPaneScaffold olarak kullanılabilir.
- Aşağıdaki bağımlılıkları ekleyip Gradle senkronizasyonu yaparak bu bileşeni edinin:
gradle/libs.versions.toml
[libraries]
androidx-material3-adaptive-layout = { module = "androidx.compose.material3.adaptive:adaptive-layout", version.ref = "material3Adaptive" }
androidx-material3-adaptive-navigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation", version.ref = "material3Adaptive" }
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive.layout)
implementation(libs.androidx.material3.adaptive.navigation)
}
- Şu anda yalnızca
ReplyListPane()çağrılarak liste bölmesini gösterenReplyApp.ktiçindeReplyAppContent()composable işlevini bulun. Aşağıdaki kodu ekleyerek bu uygulamayıListDetailPaneScaffoldile değiştirin. Bu deneysel bir API olduğundanReplyAppContent()işlevine@OptInek açıklamasını da ekleyeceksiniz:
ReplyApp.kt
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
replyHomeUIState: ReplyHomeUIState,
onEmailClick: (Email) -> Unit,
) {
val navigator = rememberListDetailPaneScaffoldNavigator<Long>()
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
ReplyListPane(replyHomeUIState, onEmailClick)
},
detailPane = {
ReplyDetailPane(replyHomeUIState.emails.first())
}
)
}
Bu kod, önce rememberListDetailPaneNavigator kullanarak bir gezgin oluşturur. Gezgin, hangi bölmenin görüntüleneceği ve bu bölmede hangi içeriğin gösterileceği konusunda bir miktar kontrol sağlar. Bu konu daha sonra açıklanacaktır.
ListDetailPaneScaffold, pencere genişliği boyutu sınıfı genişletildiğinde iki bölme gösterir. Aksi takdirde, iki parametre için sağlanan değerlere (iskele yönergesi ve iskele değeri) bağlı olarak bir bölme veya diğer bölme gösterilir. Bu kod, varsayılan davranışı elde etmek için scaffold yönergesini ve navigator tarafından sağlanan scaffold değerini kullanır.
Geriye kalan gerekli parametreler, bölmeler için oluşturulabilir lambda'lardır. ReplyListPane() ve ReplyDetailPane() (ReplyListContent.kt içinde bulunur) sırasıyla liste ve ayrıntı bölmelerinin rollerini doldurmak için kullanılır. ReplyDetailPane() bir e-posta bağımsız değişkeni beklediğinden bu kod, şimdilik ReplyHomeUIState içindeki e-posta listesinden ilk e-postayı kullanır.
Uygulamayı çalıştırın ve iki panelli düzeni görmek için emülatör görünümünü katlanabilir veya tablet olarak değiştirin (yönü de değiştirmeniz gerekebilir). Bu, eskisinden çok daha iyi görünüyor.
Şimdi bu ekranın istenen davranışlarından bazılarını ele alalım. Kullanıcı, liste bölmesinde bir e-postaya dokunduğunda bu e-posta, tüm yanıtlarıyla birlikte ayrıntı bölmesinde gösterilmelidir. Uygulama şu anda hangi e-postanın seçildiğini takip etmiyor ve bir öğeye dokunulduğunda herhangi bir işlem yapılmıyor. Bu bilgileri saklamak için en iyi yer, ReplyHomeUIState içindeki kullanıcı arayüzü durumunun geri kalan kısmıdır.
ReplyHomeViewModel.kt'ı açın veReplyHomeUIStateveri sınıfını bulun. Seçilen e-posta için varsayılan değerinullolan bir özellik ekleyin:
ReplyHomeViewModel.kt
data class ReplyHomeUIState(
val emails : List<Email> = emptyList(),
val selectedEmail: Email? = null,
val loading: Boolean = false,
val error: String? = null
)
- Aynı dosyada, kullanıcı bir liste öğesine dokunduğunda çağrılan bir
setSelectedEmail()işlevi bulunur.ReplyHomeViewModelKullanıcı arayüzü durumunu kopyalamak ve seçilen e-postayı kaydetmek için bu işlevi değiştirin:
ReplyHomeViewModel.kt
fun setSelectedEmail(email: Email) {
_uiState.update {
it.copy(selectedEmail = email)
}
}
Kullanıcı herhangi bir öğeye dokunmadan önce ne olduğunu ve seçilen e-postanın null olduğunu göz önünde bulundurmanız gerekir. Ayrıntılar bölmesinde ne gösterilmelidir? Bu durumu ele almanın birden fazla yolu vardır. Örneğin, listedeki ilk öğe varsayılan olarak gösterilebilir.
- Aynı dosyada
observeEmails()işlevini değiştirin. E-posta listesi yüklendiğinde, önceki kullanıcı arayüzü durumunda seçili bir e-posta yoksa bunu ilk öğe olarak ayarlayın:
ReplyHomeViewModel.kt
private fun observeEmails() {
viewModelScope.launch {
emailsRepository.getAllEmails()
.catch { ex ->
_uiState.value = ReplyHomeUIState(error = ex.message)
}
.collect { emails ->
val currentSelection = _uiState.value.selectedEmail
_uiState.value = ReplyHomeUIState(
emails = emails,
selectedEmail = currentSelection ?: emails.first()
)
}
}
}
ReplyApp.kt'e dönün ve varsa seçili e-postayı kullanarak ayrıntı bölmesi içeriğini doldurun:
ReplyApp.kt
ListDetailPaneScaffold(
// ...
detailPane = {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
)
Uygulamayı tekrar çalıştırın ve emülatörü tablet boyutuna geçirin. Bir liste öğesine dokunmanın ayrıntı bölmesinin içeriğini güncellediğini görün.
Bu özellik, her iki bölme de görünür olduğunda sorunsuz çalışır. Ancak pencerede yalnızca bir bölme gösterilebiliyorsa bir öğeye dokunduğunuzda hiçbir şey olmuyor gibi görünür. Emülatör görünümünü telefona veya dikey modda katlanabilir bir cihaza geçirmeyi deneyin. Bir öğeye dokunduktan sonra bile yalnızca liste bölmesinin göründüğünü fark edeceksiniz. Bunun nedeni, seçilen e-posta güncellenmesine rağmen ListDetailPaneScaffold simgesinin bu yapılandırmalarda liste bölmesine odaklanmaya devam etmesidir.
- Bu sorunu düzeltmek için
ReplyListPane'ya iletilen lambda olarak aşağıdaki kodu ekleyin:
ReplyApp.kt
ListDetailPaneScaffold(
// ...
listPane = {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
},
// ...
)
Bu lambda, bir öğe tıklandığında ek davranışlar eklemek için daha önce oluşturulan gezinme özelliğini kullanır. Bu işlev, kendisine iletilen orijinal lambda'yı çağırır ve ardından hangi bölmenin gösterilmesi gerektiğini belirten navigator.navigateTo() işlevini de çağırır. İskeledeki her bölmenin ilişkili bir rolü vardır ve ayrıntı bölmesi için bu rol ListDetailPaneScaffoldRole.Detail'dır. Daha küçük pencerelerde bu işlem, uygulamada ileri gidilmiş gibi görünür.
Uygulama, kullanıcının ayrıntılar bölmesinde geri düğmesine bastığında ne olacağını da yönetmelidir. Bu davranış, görünürde bir bölme mi yoksa iki bölme mi olduğuna bağlı olarak değişir.
- Aşağıdaki kodu ekleyerek geri gitme gezinmesini destekleyin.
ReplyApp.kt
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
replyHomeUIState: ReplyHomeUIState,
onEmailClick: (Email) -> Unit,
) {
val navigator = rememberListDetailPaneScaffoldNavigator<Long>()
BackHandler(navigator.canNavigateBack()) {
navigator.navigateBack()
}
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
AnimatedPane {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
}
},
detailPane = {
AnimatedPane {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
}
)
}
Gezgin, ListDetailPaneScaffold öğesinin tam durumunu, geri gitmenin mümkün olup olmadığını ve tüm bu senaryolarda ne yapılması gerektiğini bilir. Bu kod, gezinme aracı geri gidebildiğinde etkinleştirilen bir BackHandler oluşturur ve lambda'nın içinde navigateBack() çağrılır. Ayrıca, paneler arasındaki geçişi çok daha sorunsuz hale getirmek için her panel bir AnimatedPane() composable ile sarmalanır.
Uygulamayı tüm farklı cihaz türleri için yeniden boyutlandırılabilir bir emülatörde tekrar çalıştırın ve ekran yapılandırması her değiştiğinde veya katlanabilir bir cihazı açtığınızda gezinme ve ekran içeriğinin cihaz durumu değişikliklerine yanıt olarak dinamik bir şekilde değiştiğini fark edin. Ayrıca, liste bölmesindeki e-postalara dokunarak düzenin farklı ekranlarda nasıl davrandığını, her iki bölmeyi yan yana gösterdiğini veya aralarında sorunsuz bir şekilde animasyon yaptığını da deneyebilirsiniz.

Tebrikler, uygulamanızı her türlü cihaz durumuna ve boyutuna uyarlanabilir hale getirdiniz. Uygulamayı katlanabilir cihazlarda, tabletlerde veya diğer mobil cihazlarda çalıştırmayı deneyebilirsiniz.
6. Tebrikler
Tebrikler! Bu codelab'i başarıyla tamamladınız ve Jetpack Compose ile uygulamaları nasıl uyarlanabilir hale getireceğinizi öğrendiniz.
Cihazın boyutunu ve katlanma durumunu nasıl kontrol edeceğinizi, uygulamanızın kullanıcı arayüzünü, gezinme işlevini ve diğer işlevlerini buna göre nasıl güncelleyeceğinizi öğrendiniz. Ayrıca uyarlanabilirliğin erişilebilirliği nasıl iyileştirdiğini ve kullanıcı deneyimini nasıl geliştirdiğini de öğrendiniz.
Sırada ne var?
Compose rotasındaki diğer codelab'lere göz atın.
Örnek uygulamalar
- Compose örnekleri, codelab'lerde açıklanan en iyi uygulamaları içeren birçok uygulamanın bir araya getirilmesiyle oluşturulmuştur.