1. Pengantar
Salah satu keuntungan besar pengembangan aplikasi Anda di platform Android adalah peluang besar untuk menjangkau pengguna dalam berbagai jenis faktor bentuk, seperti perangkat wearable, perangkat foldable, tablet, desktop, dan bahkan TV. Saat menggunakan aplikasi, pengguna Anda mungkin ingin menggunakan aplikasi yang sama pada perangkat layar besar untuk memanfaatkan peningkatan properti. Pengguna Android yang menggunakan aplikasi mereka di beberapa perangkat dengan berbagai ukuran layar makin banyak, dan mereka mengharapkan pengalaman pengguna berkualitas tinggi di semua perangkat.
Sejauh ini, Anda telah belajar membuat aplikasi yang utamanya untuk perangkat seluler. Dalam codelab ini, Anda akan mempelajari cara mengubah aplikasi agar dapat menyesuaikan ukuran layar lainnya. Anda akan menggunakan pola tata letak navigasi adaptif yang bagus dan dapat digunakan untuk seluler dan perangkat berlayar lebar, seperti perangkat foldable, tablet, dan desktop.
Prasyarat
- Memahami berbagai aspek terkait pemrograman Kotlin, termasuk class, fungsi, dan kondisional
- Pemahaman dalam menggunakan class
ViewModel
- Pemahaman dalam membuat fungsi
Composables
- Pengalaman membuat tata letak dengan Jetpack Compose
- Pengalaman menjalankan aplikasi di perangkat atau emulator
Yang akan Anda pelajari
- Cara membuat navigasi antarlayar tanpa Grafik Navigasi untuk aplikasi sederhana
- Cara membuat tata letak navigasi adaptif menggunakan Jetpack Compose
- Cara membuat pengendali kembali kustom
Yang akan Anda build
- Anda akan menerapkan navigasi dinamis di aplikasi Reply yang ada agar tata letaknya beradaptasi dengan semua ukuran layar
Produk akhir akan terlihat seperti gambar di bawah ini:
Yang Anda butuhkan
- Komputer dengan akses internet, browser web, dan Android Studio
- Akses ke GitHub
2. Ringkasan aplikasi
Pengantar aplikasi Reply
Aplikasi Reply adalah aplikasi multilayar yang menyerupai program email.
Tab tersebut berisi 4 kategori berbeda yang ditampilkan oleh tab yang berbeda, yaitu: kotak masuk, terkirim, draf, dan spam.
Mendownload kode awal
Di Android Studio, buka folder basic-android-kotlin-compose-training-reply-app
.
- Buka halaman repositori GitHub yang disediakan untuk project.
- Pastikan nama cabang cocok dengan nama cabang yang ditentukan dalam codelab. Misalnya, dalam screenshot berikut, nama cabang adalah main (utama).
- Di halaman GitHub project, klik tombol Code yang akan menampilkan pop-up.
- Pada pop-up, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
- Temukan file di komputer Anda (mungkin di folder Downloads).
- Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.
Membuka project di Android Studio
- Mulai Android Studio.
- Di jendela Welcome to Android Studio, klik Open.
Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > Open.
- Di file browser, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
- Klik dua kali pada folder project tersebut.
- Tunggu Android Studio membuka project.
- Klik tombol Run untuk mem-build dan menjalankan aplikasi. Pastikan aplikasi di-build seperti yang diharapkan.
3. Panduan kode awal
Direktori penting di aplikasi Reply
Lapisan data dan UI project aplikasi Reply dipisahkan ke dalam berbagai direktori. ReplyViewModel
, ReplyUiState
, dan composable lainnya terletak di direktori ui
. Class data
dan enum
yang menentukan lapisan data dan class penyedia data terletak di direktori data
.
Inisialisasi data di aplikasi Reply
Aplikasi Reply dilakukan inisialisasi dengan data melalui metode initilizeUIState()
di ReplyViewModel
, yang dijalankan dalam fungsi init
.
ReplyViewModel.kt
...
init {
initializeUIState()
}
private fun initializeUIState() {
var mailboxes: Map<MailboxType, List<Email>> =
LocalEmailsDataProvider.allEmails.groupBy { it.mailbox }
_uiState.value =
ReplyUiState(
mailboxes = mailboxes,
currentSelectedEmail = mailboxes[MailboxType.Inbox]?.get(0)
?: LocalEmailsDataProvider.defaultEmail
)
}
...
Composable tingkat layar
Seperti aplikasi lainnya, aplikasi Reply menggunakan composable ReplyApp
sebagai composable utama tempat viewModel
dan uiState
dideklarasikan. Berbagai fungsi viewModel
juga diteruskan sebagai argumen lambda untuk composable ReplyHomeScreen
.
ReplyApp.kt
...
@Composable
fun ReplyApp(modifier: Modifier = Modifier) {
val viewModel: ReplyViewModel = viewModel()
val replyUiState = viewModel.uiState.collectAsState().value
ReplyHomeScreen(
replyUiState = replyUiState,
onTabPressed = { mailboxType: MailboxType ->
viewModel.updateCurrentMailbox(mailboxType = mailboxType)
viewModel.resetHomeScreenStates()
},
onEmailCardPressed = { email: Email ->
viewModel.updateDetailsScreenStates(
email = email
)
},
onDetailScreenBackPressed = {
viewModel.resetHomeScreenStates()
},
modifier = modifier
)
}
Composable lainnya
ReplyHomeScreen.kt
: berisi composable layar untuk layar utama, termasuk elemen navigasi.ReplyHomeContent.kt
: berisi composable yang menentukan composable layar utama yang lebih mendetail.ReplyDetailsScreen.kt
: berisi composable layar dan composable yang lebih kecil untuk layar detail.
Anda dapat membaca setiap file secara mendetail untuk mendapatkan pemahaman yang lebih baik tentang composable sebelum melanjutkan ke bagian codelab berikutnya.
4. Mengubah layar tanpa grafik navigasi
Di jalur sebelumnya, Anda telah mempelajari cara menggunakan class NavHostController
untuk berpindah dari satu layar ke layar lainnya. Dengan Compose, Anda juga dapat mengubah layar dengan pernyataan bersyarat sederhana dengan menggunakan status runtime yang dapat diubah. Ini sangat berguna terutama pada aplikasi kecil seperti aplikasi Reply, karena Anda hanya ingin beralih di antara dua layar.
Mengubah layar dengan perubahan status
Di Compose, layar dikomposisi ulang saat terjadi perubahan status. Anda dapat mengubah layar menggunakan kondisional sederhana untuk merespons perubahan status.
Anda akan menggunakan kondisional untuk menampilkan konten layar utama saat pengguna berada di layar utama, dan layar detail saat pengguna tidak berada di layar utama.
Modifikasi aplikasi Reply untuk mengizinkan perubahan layar saat status berubah dengan menyelesaikan langkah berikut:
- Buka kode awal di Android Studio.
- Di composable
ReplyHomeScreen
diReplyHomeScreen.kt
, gabungkan composableReplyAppContent
dengan pernyataanif
saat propertiisShowingHomepage
dari objekreplyUiState
adalahtrue
.
ReplyHomeScreen.kt
@Composable
fun ReplyHomeScreen(
replyUiState: ReplyUiState,
onTabPressed: (MailboxType) -> Unit = {},
onEmailCardPressed: (Int) -> Unit = {},
onDetailScreenBackPressed: () -> Unit = {},
modifier: Modifier = Modifier
) {
...
if (replyUiState.isShowingHomepage) {
ReplyAppContent(
replyUiState = replyUiState,
onTabPressed = onTabPressed,
onEmailCardPressed = onEmailCardPressed,
navigationItemContentList = navigationItemContentList,
modifier = modifier
)
}
}
Anda kini harus memperhitungkan skenario saat pengguna tidak ada di layar utama dengan menampilkan layar detail.
- Tambahkan cabang
else
dengan composableReplyDetailsScreen
di isinya. MenambahkanreplyUIState
,onDetailScreenBackPressed
, danmodifier
sebagai argumen untuk composableReplyDetailsScreen
.
ReplyHomeScreen.kt
@Composable
fun ReplyHomeScreen(
replyUiState: ReplyUiState,
onTabPressed: (MailboxType) -> Unit = {},
onEmailCardPressed: (Int) -> Unit = {},
onDetailScreenBackPressed: () -> Unit = {},
modifier: Modifier = Modifier
) {
...
if (replyUiState.isShowingHomepage) {
ReplyAppContent(
replyUiState = replyUiState,
onTabPressed = onTabPressed,
onEmailCardPressed = onEmailCardPressed,
navigationItemContentList = navigationItemContentList,
modifier = modifier
)
} else {
ReplyDetailsScreen(
replyUiState = replyUiState,
onBackPressed = onDetailScreenBackPressed,
modifier = modifier
)
}
}
Objek replyUiState
adalah objek status. Dengan demikian, jika ada perubahan pada properti isShowingHomepage
dari objek replyUiState
, composable ReplyHomeScreen
akan dibuat ulang dan pernyataan if/else
akan dievaluasi ulang saat runtime. Pendekatan ini mendukung navigasi antarlayar yang berbeda tanpa menggunakan class NavHostController
.
Membuat pengendali kembali kustom
Salah satu keuntungan menggunakan composable NavHost
untuk beralih antarlayar adalah rute layar sebelumnya disimpan di data sebelumnya. Layar yang disimpan ini memungkinkan tombol kembali sistem menavigasi dengan mudah ke layar sebelumnya saat dipanggil. Karena aplikasi Reply tidak menggunakan NavHost
, Anda harus menambahkan kode untuk menangani tombol kembali secara manual. Anda akan melakukannya nanti.
Selesaikan langkah-langkah berikut untuk membuat pengendali kembali kustom di aplikasi Reply:
- Pada baris pertama composable
ReplyDetailsScreen
, tambahkan composableBackHandler
. - Panggil fungsi
onBackPressed()
dalam isi composableBackHandler
.
ReplyDetailsScreen.kt
...
import androidx.activity.compose.BackHandler
...
@Composable
fun ReplyDetailsScreen(
replyUiState: ReplyUiState,
modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
) {
BackHandler {
onBackPressed()
}
...
5. Menjalankan aplikasi di perangkat layar besar
Memeriksa aplikasi dengan emulator yang dapat diubah ukurannya
Untuk membuat aplikasi yang dapat digunakan, developer harus memahami pengalaman pengguna dalam berbagai faktor bentuk. Oleh karena itu, Anda harus menguji aplikasi pada berbagai faktor bentuk dari awal proses pengembangan.
Anda dapat menggunakan banyak emulator dengan berbagai ukuran layar untuk mencapai sasaran ini. Namun, melakukannya bisa jadi rumit, terutama saat Anda mem-build untuk beberapa ukuran layar sekaligus. Anda mungkin juga perlu menguji bagaimana aplikasi yang berjalan merespons perubahan ukuran layar, seperti perubahan orientasi, perubahan ukuran jendela di desktop, dan perubahan status lipat di perangkat foldable.
Android Studio membantu Anda menguji skenario ini dengan memperkenalkan emulator yang dapat diubah ukurannya.
Selesaikan langkah-langkah berikut untuk menyiapkan emulator yang dapat diubah ukurannya:
- Pastikan Anda menjalankan Android Studio Chipmunk | 2021.2.1 atau lebih tinggi.
- Di Android Studio, pilih Tools > Device Manager.
- Di Device Manager, klik Create device.
- Pilih kategori Phone dan perangkat Resizable (Experimental).
- Klik Berikutnya.
- Pilih API Level 33.
- Klik Berikutnya.
- Beri nama Android Virtual Device baru Anda.
- Klik Finish.
Menjalankan aplikasi pada emulator perangkat layar besar
Setelah penyiapan emulator yang dapat diubah ukurannya, mari kita lihat tampilan aplikasi di layar besar.
- Jalankan aplikasi di emulator yang dapat diubah ukurannya.
- Pilih Tablet untuk mode tampilan.
- Periksa aplikasi dalam mode Tablet dalam mode lanskap.
Perhatikan bahwa tampilan layar tablet dibuat panjang secara horizontal. Meskipun fungsional, orientasi ini mungkin bukan penggunaan real estate layar besar yang terbaik. Mari kita bahas masalah ini berikutnya.
Desain untuk perangkat layar besar
Saat pertama kali melihat aplikasi ini di tablet, pikiran Anda adalah salah desain dan tidak menarik. Tepat sekali: tata letak ini tidak didesain untuk penggunaan pada perangkat layar besar.
Saat membuat desain untuk perangkat layar besar, seperti tablet dan perangkat foldable, Anda harus mempertimbangkan ergonomi pengguna dan kedekatan jari pengguna dengan layar. Dengan perangkat seluler, jari pengguna dapat dengan mudah menjangkau sebagian besar layar; lokasi elemen interaktif, seperti tombol dan elemen navigasi, tidak terlalu penting. Namun, untuk layar besar, memiliki elemen interaktif penting di bagian tengah layar dapat membuatnya sulit dijangkau.
Seperti yang Anda lihat di aplikasi Reply, desain untuk perangkat layar besar tidak hanya meregangkan atau memperbesar elemen UI agar sesuai dengan layar. Ini adalah peluang untuk menggunakan properti yang ditingkatkan untuk menciptakan pengalaman yang berbeda bagi pengguna Anda. Misalnya, Anda dapat menambahkan tata letak lain di layar yang sama untuk mencegah keharusan menavigasi ke layar lain atau memungkinkan multitasking.
Desain ini dapat meningkatkan produktivitas pengguna dan mendorong interaksi yang lebih besar. Namun, sebelum men-deploy desain ini, Anda harus terlebih dahulu mempelajari cara membuat tata letak yang berbeda untuk ukuran layar yang berbeda.
6. Membuat tata letak beradaptasi dengan berbagai ukuran layar
Apa itu titik henti sementara?
Anda mungkin bertanya-tanya bagaimana Anda dapat menampilkan berbagai tata letak untuk aplikasi yang sama. Jawaban singkatnya adalah dengan menggunakan kondisional pada berbagai status, seperti yang Anda lakukan di awal codelab ini.
Untuk membuat aplikasi adaptif, Anda memerlukan tata letak untuk berubah berdasarkan ukuran layar. Titik pengukuran yang perubahan tata letaknya dikenal sebagai titik henti sementara. Desain Material membuat rentang titik henti sementara yang tidak sesuai yang mencakup sebagian besar layar Android.
Tabel rentang titik henti sementara ini menunjukkan, misalnya, jika aplikasi Anda saat ini berjalan di perangkat dengan ukuran layar kurang dari 600 dp, Anda harus menampilkan tata letak seluler.
Menggunakan Window Size Class
WindowSizeClass
API yang diperkenalkan untuk Compose membuat penerapan titik henti sementara Desain Material lebih sederhana.
Window Size Class memperkenalkan tiga kategori ukuran: Ringkas, Sedang, dan Diperluas, untuk lebar dan tinggi.
Selesaikan langkah berikut untuk menerapkan WindowSizeClass
API di aplikasi Reply:
- Tambahkan dependensi
material3-window-size-class
ke filebuild.gradle
modul.
build.gradle
...
dependencies {
...
"androidx.compose.material3:material3-window-size-class:$material3_version"
...
- Klik Sync Now untuk menyinkronkan gradle setelah menambahkan dependensi.
Dengan file build.grade
terbaru, Anda kini dapat membuat variabel yang menyimpan ukuran jendela aplikasi pada waktu tertentu.
- Pada fungsi
onCreate()
di fileMainActivity.kt
, tetapkan metodecalculateWindowSizeClass
dengan konteksthis
yang diteruskan dalam parameter ke variabel bernamawindowSize
. - Impor paket
calculateWindowSizeClass
yang sesuai.
MainActivity.kt
...
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ReplyTheme {
val windowSize = calculateWindowSizeClass(this)
ReplyApp()
...
- Perhatikan garis bawah merah sintaksis
calculateWindowSizeClass
, yang menampilkan bohlam merah. Klik bohlam merah di sebelah kiri variabelwindowSize
dan pilih Opt in for ‘ExperimentalMaterial3WindowSizeClassApi' di ‘onCreate' untuk membuat anotasi di atas metodeonCreate()
.
Anda dapat menggunakan variabel WindowWidthSizeClass
di MainActivity.kt
untuk menentukan tata letak mana yang akan ditampilkan di berbagai composable. Mari siapkan composable ReplyApp
untuk menerima nilai ini.
- Dalam file
ReplyApp.kt
, ubah composableReplyApp
untuk menerimaWindowWidthSizeClass
sebagai parameter dan impor paket yang sesuai.
ReplyApp.kt
...
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
...
@Composable
fun ReplyApp(
windowSize: WindowWidthSizeClass,
modifier: Modifier = Modifier
) {
...
- Teruskan variabel
windowSize
ke komponenReplyApp
dalam metodeonCreate()
fileMainActivity.kt
.
MainActivity.kt
...
setContent {
ReplyTheme {
val windowSize = calculateWindowSizeClass(this)
ReplyApp(
windowSize = windowSize.widthSizeClass
)
...
Anda juga harus memperbarui pratinjau aplikasi untuk parameter windowSize
.
- Teruskan
WindowWidthSizeClass.Compact
sebagai parameterwindowSize
ke composableReplyApp
untuk komponen pratinjau, lalu impor paket yang sesuai.
MainActivity.kt
...
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
...
@Preview(showBackground = true)
@Composable
fun ReplyAppPreview() {
ReplyTheme {
ReplyApp(
windowSize = WindowWidthSizeClass.Compact,
)
}
}
- Untuk mengubah tata letak aplikasi berdasarkan ukuran layar, tambahkan pernyataan
when
dalam composableReplyApp
berdasarkan nilaiWindowWidthSizeClass
.
ReplyApp.kt
...
@Composable
fun ReplyApp(
windowSize: WindowWidthSizeClass,
modifier: Modifier = Modifier
) {
val viewModel: ReplyViewModel = viewModel()
val replyUiState = viewModel.uiState.collectAsState().value
when (windowSize) {
WindowWidthSizeClass.Compact -> {
}
WindowWidthSizeClass.Medium -> {
}
WindowWidthSizeClass.Expanded -> {
}
else -> {
}
}
...
Pada tahap ini, Anda telah menetapkan dasar untuk menggunakan nilai WindowSizeClass
guna mengubah tata letak di aplikasi. Langkah berikutnya adalah menentukan tampilan aplikasi yang Anda inginkan pada ukuran layar yang berbeda.
7. Mengimplementasikan tata letak navigasi adaptif
Mengimplementasikan navigasi UI adaptif
Saat ini, navigasi bawah digunakan untuk semua ukuran layar.
Seperti yang telah dibahas sebelumnya, elemen navigasi ini tidak ideal karena pengguna dapat mengalami kesulitan untuk menjangkau elemen navigasi yang penting ini di layar yang lebih besar. Untungnya, ada pola yang direkomendasikan untuk berbagai elemen navigasi untuk berbagai class ukuran jendela di navigasi untuk UI yang responsif. Untuk aplikasi Reply, Anda dapat menerapkan elemen berikut:
Kolom samping navigasi adalah komponen navigasi lain dengan desain material yang memungkinkan opsi navigasi ringkas untuk tujuan utama dapat diakses dari sisi aplikasi.
Demikian pula, panel navigasi persisten/permanen dibuat oleh desain material sebagai opsi lain untuk memberikan akses ergonomis untuk layar yang lebih besar.
Mengimplementasikan panel navigasi
Untuk membuat panel navigasi bagi layar yang diperluas, Anda dapat menggunakan parameter navigationType
. Selesaikan langkah-langkah berikut untuk melakukannya:
- Untuk merepresentasikan berbagai jenis elemen navigasi, buat file baru
WindowStateUtils.kt
dalam paketutils
baru, yang berada di direktoriui
. - Tambahkan class
Enum
untuk mewakili berbagai jenis elemen navigasi.
WindowStateUtils.kt
package com.example.reply.ui.utils
enum class ReplyNavigationType {
BOTTOM_NAVIGATION, NAVIGATION_RAIL, PERMANENT_NAVIGATION_DRAWER
}
Agar berhasil menerapkan panel navigasi, Anda perlu menentukan jenis navigasi berdasarkan ukuran jendela aplikasi.
- Pada composable
ReplyApp
, buat variabelnavigationType
dan tetapkan nilaiReplyNavigationType
yang sesuai, sesuai dengan ukuran layar dalam pernyataanwhen
.
ReplyApp.kt
...
import com.example.reply.ui.utils.ReplyNavigationType
...
when (windowSize) {
WindowWidthSizeClass.Compact -> {
navigationType = ReplyNavigationType.BOTTOM_NAVIGATION
}
WindowWidthSizeClass.Medium -> {
navigationType = ReplyNavigationType.NAVIGATION_RAIL
}
WindowWidthSizeClass.Expanded -> {
navigationType = ReplyNavigationType.PERMANENT_NAVIGATION_DRAWER
}
else -> {
navigationType = ReplyNavigationType.BOTTOM_NAVIGATION
}
}
...
Anda dapat menggunakan nilai navigationType
dalam composable ReplyHomeScreen
. Anda dapat mempersiapkannya dengan menjadikannya parameter untuk composable.
- Pada composable
ReplyHomeScreen
, tambahkannavigationType
sebagai parameter.
ReplyHomeScreen.kt
...
@Composable
fun ReplyHomeScreen(
navigationType: ReplyNavigationType,
replyUiState: ReplyUiState,
onTabPressed: (MailboxType) -> Unit = {},
onEmailCardPressed: (Email) -> Unit = {},
onDetailScreenBackPressed: () -> Unit = {},
modifier: Modifier = Modifier
)
...
- Teruskan
navigationType
ke composableReplyHomeScreen
.
ReplyApp.kt
...
ReplyHomeScreen(
navigationType = navigationType,
replyUiState = replyUiState,
onTabPressed = { mailboxType: MailboxType ->
viewModel.updateCurrentMailbox(mailboxType = mailboxType)
viewModel.resetHomeScreenStates()
},
onEmailCardPressed = { email: Email ->
viewModel.updateDetailsScreenStates(
email = email
)
},
onDetailScreenBackPressed = {
viewModel.resetHomeScreenStates()
},
modifier = modifier
)
...
Selanjutnya, Anda dapat membuat cabang untuk menampilkan konten aplikasi dengan panel navigasi saat pengguna membuka aplikasi pada layar yang diperluas dan menampilkan layar utama.
- Dalam isi composable
ReplyHomeScreen
, tambahkan pernyataanif
untuk kondisinavigationType == ReplyNavigationType.PERMANENT_NAVIGATION_DRAWER && replyUiState.isShowingHomepage
.
ReplyHomeScreen.kt
import androidx.compose.material3.PermanentNavigationDrawer
...
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ReplyHomeScreen(
navigationType: ReplyNavigationType,
replyUiState: ReplyUiState,
onTabPressed: (MailboxType) -> Unit = {},
onEmailCardPressed: (Email) -> Unit = {},
onDetailScreenBackPressed: () -> Unit = {},
modifier: Modifier = Modifier
) {
...
if (navigationType == ReplyNavigationType.PERMANENT_NAVIGATION_DRAWER
&& replyUiState.isShowingHomepage
) {
}
if (replyUiState.isShowingHomepage) {
ReplyAppContent(
replyUiState = replyUiState,
...
- Untuk membuat panel samping permanen, buat composable
PermanentNavigationDrawer
dalam isi pernyataan if dan tambahkan composableNavigationDrawerContent
sebagai input untuk parameterdrawerContent
. - Tambahkan composable
ReplyAppContent
sebagai argumen lambda final dariPermanentNavigationDrawer
.
ReplyHomeScreen.kt
...
if (navigationType == ReplyNavigationType.PERMANENT_NAVIGATION_DRAWER
&& replyUiState.isShowingHomepage
) {
PermanentNavigationDrawer(
drawerContent = {
NavigationDrawerContent(
selectedDestination = replyUiState.currentMailbox,
onTabPressed = onTabPressed,
navigationItemContentList = navigationItemContentList
)
}
) {
ReplyAppContent(
replyUiState = replyUiState,
onTabPressed = onTabPressed,
onEmailCardPressed = onEmailCardPressed,
navigationItemContentList = navigationItemContentList,
modifier = modifier
)
}
}
...
- Tambahkan cabang
else
yang menggunakan isi composable sebelumnya untuk mempertahankan cabang sebelumnya untuk layar yang tidak diperluas.
ReplyHomeScreen.kt
...
if (navigationType == ReplyNavigationType.PERMANENT_NAVIGATION_DRAWER
&& replyUiState.isShowingHomepage
) {
PermanentNavigationDrawer(
drawerContent = {
NavigationDrawerContent(
selectedDestination = replyUiState.currentMailbox,
onTabPressed = onTabPressed,
navigationItemContentList = navigationItemContentList
)
}
) {
ReplyAppContent(
replyUiState = replyUiState,
onTabPressed = onTabPressed,
onEmailCardPressed = onEmailCardPressed,
navigationItemContentList = navigationItemContentList,
modifier = modifier
)
}
} else {
if (replyUiState.isShowingHomepage) {
ReplyAppContent(
replyUiState = replyUiState,
onTabPressed = onTabPressed,
onEmailCardPressed = onEmailCardPressed,
navigationItemContentList = navigationItemContentList,
modifier = modifier
)
} else {
ReplyDetailsScreen(
replyUiState = replyUiState,
onBackPressed = onDetailScreenBackPressed,
modifier = modifier
)
}
}
}
...
- Tambahkan anotasi eksperimental ke composable
ReplyHomeScreen
. Anda memerlukannya karenaPermanentNavigationDrawer
API masih bersifat eksperimental.
ReplyHomeScreen.kt
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ReplyHomeScreen(
navigationType: ReplyNavigationType,
replyUiState: ReplyUiState,
onTabPressed: (MailboxType) -> Unit = {},
onEmailCardPressed: (Email) -> Unit = {},
onDetailScreenBackPressed: () -> Unit = {},
modifier: Modifier = Modifier
) {
...
- Jalankan aplikasi dalam mode Tablet. Anda akan melihat layar berikut:
Mengimplementasikan kolom samping navigasi
Serupa dengan implementasi panel navigasi, Anda harus menggunakan parameter navigationType
untuk beralih di antara elemen navigasi.
Pertama, mari kita tambahkan kolom samping navigasi untuk layar berukuran sedang.
- Mulai dengan menyiapkan composable
ReplyAppContent
dengan menambahkannavigationType
sebagai parameter.
ReplyHomeScreen.kt
...
@Composable
private fun ReplyAppContent(
navigationType: ReplyNavigationType,
replyUiState: ReplyUiState,
onTabPressed: ((MailboxType) -> Unit) = {},
onEmailCardPressed: (Email) -> Unit = {},
navigationItemContentList: List<NavigationItemContent>,
modifier: Modifier = Modifier
) {
...
- Teruskan nilai
navigationType
ke kedua composableReplyAppContent
.
ReplyHomeScreen.kt
...
ReplyAppContent(
navigationType = navigationType,
replyUiState = replyUiState,
onTabPressed = onTabPressed,
onEmailCardPressed = onEmailCardPressed,
navigationItemContentList = navigationItemContentList,
modifier = modifier
)
}
} else {
if (replyUiState.isShowingHomepage) {
ReplyAppContent(
navigationType = navigationType,
replyUiState = replyUiState,
onTabPressed = onTabPressed,
onEmailCardPressed = onEmailCardPressed,
navigationItemContentList = navigationItemContentList,
modifier = modifier
)
...
Selanjutnya, mari kita tambahkan cabang, yang memungkinkan aplikasi menampilkan kolom samping navigasi untuk beberapa skenario.
- Di baris pertama isi composable
ReplyAppContent
, gabungkan composableReplyNavigationRail
di sekitar composableAnimatedVisibility
dan setel parametervisibility
menjaditrue
jika nilaiReplyNavigationType
adalahNavigationRail
.
ReplyHomeScreen.kt
...
@Composable
private fun ReplyAppContent(
navigationType: ReplyNavigationType,
replyUiState: ReplyUiState,
onTabPressed: ((MailboxType) -> Unit) = {},
onEmailCardPressed: (Email) -> Unit = {},
navigationItemContentList: List<NavigationItemContent>,
modifier: Modifier = Modifier
) {
AnimatedVisibility(visible = navigationType == ReplyNavigationType.NAVIGATION_RAIL) {
ReplyNavigationRail(
currentTab = replyUiState.currentMailbox,
onTabPressed = onTabPressed,
navigationItemContentList = navigationItemContentList
)
}
Column(
modifier = Modifier
.fillMaxSize() .background(MaterialTheme.colorScheme.inverseOnSurface)
) {
ReplyListOnlyContent(
replyUiState = replyUiState,
onEmailCardPressed = onEmailCardPressed,
modifier = Modifier.weight(1f)
)
ReplyBottomNavigationBar(
currentTab = replyUiState.currentMailbox,
onTabPressed = onTabPressed,
navigationItemContentList = navigationItemContentList
)
}
}
...
- Untuk meratakan composable dengan benar, gabungkan composable
AnimatedVisibility
dan composableColumn
yang ditemukan dalam isiReplyAppContent
di composableRow
.
ReplyHomeScreen.kt
...
@Composable
private fun ReplyAppContent(
navigationType: ReplyNavigationType,
replyUiState: ReplyUiState,
onTabPressed: ((MailboxType) -> Unit) = {},
onEmailCardPressed: (Email) -> Unit = {},
navigationItemContentList: List<NavigationItemContent>,
modifier: Modifier = Modifier
) {
Row(modifier = modifier.fillMaxSize()) {
AnimatedVisibility(visible = navigationType == ReplyNavigationType.NAVIGATION_RAIL) {
ReplyNavigationRail(
currentTab = replyUiState.currentMailbox,
onTabPressed = onTabPressed,
navigationItemContentList = navigationItemContentList
)
}
Column(
modifier = Modifier
.fillMaxSize() .background(MaterialTheme.colorScheme.inverseOnSurface)
) {
ReplyListOnlyContent(
replyUiState = replyUiState,
onEmailCardPressed = onEmailCardPressed,
modifier = Modifier.weight(1f)
)
ReplyBottomNavigationBar(
currentTab = replyUiState.currentMailbox,
onTabPressed = onTabPressed,
navigationItemContentList = navigationItemContentList
)
}
}
}
...
Terakhir, pastikan navigasi bawah ditampilkan dalam beberapa skenario.
- Setelah composable
ReplyListOnlyContent
, gabungkan composableReplyBottomNavigationBar
dengan composableAnimatedVisibility
. - Tetapkan parameter
visible
saat nilaiReplyNavigationType
adalahBOTTOM_NAVIGATION
.
ReplyHomeScreen.kt
...
ReplyListOnlyContent(
replyUiState = replyUiState,
onEmailCardPressed = onEmailCardPressed,
modifier = Modifier.weight(1f)
)
AnimatedVisibility(visible = navigationType == ReplyNavigationType.BOTTOM_NAVIGATION) {
ReplyBottomNavigationBar(
currentTab = replyUiState.currentMailbox,
onTabPressed = onTabPressed,
navigationItemContentList = navigationItemContentList
)
}
...
- Jalankan aplikasi dalam mode perangkat foldable yang ditutup. Anda akan melihat layar berikut:
8. Mendapatkan kode solusi
Guna mendownload kode untuk codelab yang sudah selesai, Anda dapat menggunakan perintah git ini:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-reply-app.git cd basic-android-kotlin-compose-training-reply-app git checkout nav-update
Atau, Anda dapat mendownload repositori sebagai file ZIP, lalu mengekstraknya, dan membukanya di Android Studio.
Jika Anda ingin melihat kode solusi, lihat di GitHub.
9. Kesimpulan
Selamat! Anda selangkah lebih dekat untuk membuat aplikasi Reply dapat menyesuaikan semua ukuran layar dengan menerapkan tata letak navigasi adaptif. Anda meningkatkan pengalaman pengguna menggunakan banyak faktor bentuk Android. Pada codelab berikutnya, Anda akan meningkatkan keterampilan menggunakan aplikasi adaptif dengan menerapkan tata letak, pengujian, dan pratinjau konten adaptif.
Jangan lupa untuk membagikan karya Anda di media sosial dengan #AndroidBasics.