1. Sebelum memulai
SociaLite menunjukkan cara menggunakan berbagai API platform Android untuk mengimplementasikan fitur yang biasa terlihat di aplikasi jejaring sosial, memanfaatkan beragam API Jetpack untuk mencapai fungsi kompleks yang berfungsi dengan andal di lebih banyak perangkat dan memerlukan lebih sedikit kode.
Codelab ini memandu Anda melalui proses pembuatan aplikasi SociaLite yang kompatibel dengan penerapan layar penuh di Android 15 dan menampilkan aplikasi dalam layar penuh dengan cara yang kompatibel dengan versi lama. Setelah ditampilkan di layar penuh, SociaLite akan terlihat seperti berikut, bergantung pada perangkat dan mode navigasi Anda:
SociaLite dengan navigasi tiga tombol | SociaLite dengan navigasi gestur |
SociaLite di perangkat layar besar |
Prasyarat
- Pengetahuan Kotlin dasar.
- Penyelesaian codelab Menyiapkan Android Studio, atau memahami cara menggunakan Android Studio dan menguji aplikasi di emulator atau di perangkat fisik yang menjalankan Android 15.
Yang Anda pelajari
- Cara menangani penerapan layar penuh di Android 15.
- Cara menampilkan aplikasi di layar penuh agar kompatibel dengan versi lama.
Yang Anda perlukan
- Versi terbaru Android Studio.
- Perangkat pengujian atau emulator yang menjalankan Android 15 Beta 1 atau yang lebih baru.
- SDK Android 15 Beta 1 atau yang lebih baru.
2. Mendapatkan kode awal
- Download kode awal dari GitHub.
Selain itu, Anda juga dapat meng-clone repositori dan memeriksa cabang codelab_improve_android_experience_2024
.
$ git clone git@github.com:android/socialite.git
$ cd socialite
$ git checkout codelab_improve_android_experience_2024
- Buka SociaLite di Android Studio dan jalankan aplikasi di perangkat atau emulator Android 15 Anda. Anda akan melihat layar yang tampak seperti berikut:
Navigasi tiga tombol | Navigasi gestur |
Perangkat layar besar |
- Di halaman Chats, pilih salah satu percakapan, misalnya percakapan dengan anjing.
Pesan chat Dog dengan navigasi tiga tombol | Pesan chat Dog dengan navigasi gestur |
3. Menampilkan aplikasi Anda dengan layar penuh di Android 15
Apa itu tata letak layar penuh?
Aplikasi dapat menggambar di balik kolom sistem, sehingga memungkinkan pengalaman pengguna yang lebih baik dan penggunaan ruang layar secara penuh. Hal ini disebut tampilan layar penuh.
Cara menangani penerapan layar penuh di Android 15
Sebelum Android 15, tata letak UI aplikasi Anda secara default dibatasi untuk menghindari area kolom sistem, seperti status bar dan menu navigasi. Aplikasi dapat ditampilkan dalam layar penuh. Bergantung pada aplikasinya, mengaktifkan opsi ini bisa jadi hal yang mudah hingga rumit.
Mulai Android 15, aplikasi Anda akan ditampilkan dalam layar penuh secara default. Anda akan melihat default berikut:
- Menu navigasi tiga tombol transparan.
- Menu navigasi gestur transparan.
- Status bar transparan.
- Kecuali menerapkan inset atau padding, konten akan digambar di belakang kolom sistem, seperti menu navigasi, status bar, dan kolom teks.
Hal ini memastikan tampilan layar penuh tidak diabaikan sebagai cara untuk meningkatkan kualitas aplikasi dan mengurangi pekerjaan yang dibutuhkan aplikasi Anda untuk menerapkan tampilan layar penuh. Namun, perubahan ini mungkin berdampak negatif pada aplikasi Anda. Anda akan melihat dua contoh dampak negatif dalam SociaLite setelah mengupgrade SDK target ke Android 15.
Mengubah nilai SDK target ke Android 15
- Dalam file build.gradle aplikasi SociaLite, ubah target dan kompilasi versi SDK ke Android 15 atau
VanillaIceCream
.
Jika Anda menggunakan codelab ini sebelum rilis stabil Android 15, kodenya akan terlihat seperti ini:
android {
namespace = "com.google.android.samples.socialite"
compileSdkPreview = "VanillaIceCream"
defaultConfig {
applicationId = "com.google.android.samples.socialite"
minSdk = 21
targetSdkPreview = "VanillaIceCream"
...
}
...
}
Jika Anda menggunakan codelab ini setelah rilis stabil Android 15, kodenya akan terlihat seperti ini:
android {
namespace = "com.google.android.samples.socialite"
compileSdk = 35
defaultConfig {
applicationId = "com.google.android.samples.socialite"
minSdk = 21
targetSdk = 35
...
}
...
}
- Bangun kembali SociaLite dan amati masalah berikut:
- Perlindungan latar belakang navigasi tiga tombol tidak sesuai dengan menu navigasi. Layar Chats ditampilkan dalam layar penuh tanpa intervensi apa pun untuk navigasi gestur dari Anda. Namun, ada perlindungan latar belakang navigasi tiga tombol yang harus dihapus.
Layar Chats dengan navigasi tiga tombol | Layar Chats dengan navigasi gestur |
- UI Tertutup. Terdapat elemen UI di bagian bawah percakapan yang tertutup oleh menu navigasi. Hal ini paling jelas terlihat dalam navigasi tiga tombol.
Pesan chat Dog dengan navigasi tiga tombol | Pesan chat Dog dengan navigasi gestur |
Memperbaiki SociaLite
Untuk menghapus perlindungan latar belakang navigasi tiga tombol default, ikuti langkah-langkah berikut:
- Dalam file
MainActivity.kt
, hapus perlindungan latar belakang default dengan menyetel properti window.isNavigationBarContrastEnforced ke salah (false).
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
setContent {
// Add this block:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.isNavigationBarContrastEnforced = false
}
}
}
...
}
window.isNavigationBarContrastEnforced
memastikan bahwa menu navigasi memiliki kontras yang cukup ketika latar belakang transparan penuh diminta. Dengan menyetel atribut ini ke salah (false), Anda efektif menyetel latar belakang navigasi tiga tombol menjadi transparan. window.isNavigationBarContrastEnforced
hanya akan berdampak pada navigasi tiga tombol dan tidak berdampak pada navigasi gestur.
- Jalankan kembali aplikasi dan lihat salah satu percakapan di perangkat Android 15 Anda. Layar Timeline, Chats, dan Settings kini ditampilkan dalam layar penuh.
NavigationBar
aplikasi (dengan tombol Timeline, Chats, dan Settings) digambar di belakang menu navigasi tiga tombol transparan sistem.
Layar Chats dengan banding dihapus | Tidak ada perubahan dalam navigasi gestur |
Namun, perhatikan bahwa InputBar
percakapan masih tertutup oleh kolom sistem. Anda harus menangani inset dengan benar untuk memperbaiki masalah ini.
Percakapan Dog dalam navigasi tiga tombol. Kolom input di bagian bawah tertutup oleh menu navigasi sistem. | Percakapan Dog dalam navigasi gestur. Kolom input di bagian bawah tertutup oleh menu navigasi sistem. |
Di SociaLite, InputBar
tertutup. Dalam praktiknya, Anda mungkin menemukan elemen di bagian atas, bawah, kiri, dan kanan tertutupi saat memutar ke mode lanskap atau saat menggunakan perangkat layar besar. Anda perlu mempertimbangkan cara menangani inset untuk semua kasus penggunaan ini. Untuk SociaLite, Anda menerapkan padding untuk menempelkan konten InputBar
yang dapat diketuk.
Untuk menerapkan inset guna memperbaiki UI yang tertutup, ikuti langkah-langkah berikut:
- Buka file
ui/chat/ChatScreen.kt
, lalu cari composableChatContent
di sekitar baris 178, yang berisi UI untuk layar percakapan.ChatContent
memanfaatkanScaffold
untuk mengonstruksi UI dengan mudah. Secara default,Scaffold
memberikan informasi tentang UI sistem, seperti kedalaman kolom sistem sebagai inset yang dapat Anda gunakan dengan nilai paddingScaffold
(parameterinnerPadding
). Tambahkan padding menggunakaninnerPadding
Scaffold
keInputBar
. - Temukan
InputBar
dalamChatContent
di dekat baris 214. Composable ini adalah composable kustom yang membuat UI bagi pengguna agar dapat menulis pesan. Pratinjaunya terlihat seperti ini:
InputBar
mengambil contentPadding
dan menerapkannya sebagai padding ke composable Baris yang berisi UI lainnya. Padding akan diterapkan ke semua sisi composable Baris. Anda dapat melihat ini di sekitar baris 432. Berikut composable InputBar
untuk referensi (jangan menambahkan kode ini):
// Don't add this code because it's only for reference.
@Composable
private fun InputBar(
contentPadding: PaddingValues,
...,
) {
Surface(...) {
Row(
modifier = Modifier
.padding(contentPadding)
...
) {
IconButton(...) { ... } // take picture
IconButton(...) { ... } // attach picture
TextField(...) // write message
FilledIconButton(...){ ... } // send message
}
}
}
}
- Kembali ke
InputBar
dalamChatContent
dan ubahcontentPadding
untuk menggunakan inset kolom sistem. Fungsi ini ada di sekitar baris 220.
InputBar(
...
contentPadding = innerPadding, //Add this line.
// contentPadding = PaddingValues(0.dp), // Remove this line.
...
)
- Jalankan kembali aplikasi di perangkat Android 15.
Percakapan Dog dalam navigasi tiga tombol dengan inset yang tidak diterapkan dengan benar. | Percakapan Dog dalam navigasi gestur dengan inset yang tidak diterapkan dengan benar. |
Padding bawah diterapkan agar tombol tidak lagi tertutup oleh kolom sistem. Selain itu, padding atas juga diterapkan. Padding atas mencakup kedalaman TopAppBar
dan kolom sistem. Scaffold meneruskan nilai padding ke kontennya agar dapat menghindari panel aplikasi atas serta kolom sistem.
- Untuk memperbaiki padding atas, buat salinan
PaddingValues
innerPadding
, tetapkan padding atas ke0.dp
, dan teruskan salinan yang diubah kecontentPadding
.
InputBar(
...
contentPadding = innerPadding.copy(layoutDirection, top = 0.dp), //Add this line.
// contentPadding = innerPadding, // Remove this line.
...
)
- Jalankan kembali aplikasi di perangkat Android 15.
Percakapan Dog dalam navigasi tiga tombol dengan inset yang diterapkan dengan benar. | Percakapan Dog dalam navigasi gestur dengan inset yang diterapkan dengan benar. |
Selamat! Anda telah membuat SociaLite kompatibel dengan perubahan platform tampilan layar penuh Android 15. Berikutnya, Anda akan mempelajari cara menampilkan SociaLite dalam layar penuh agar kompatibel dengan versi lama.
4. Menampilkan SociaLite dalam layar penuh agar kompatibel dengan versi lama
SociaLite kini ditampilkan dalam layar penuh di Android 15, tetapi belum di perangkat Android lama. Untuk menampilkan SociaLite dalam layar penuh di perangkat Android lama, panggil enableEdgeToEdge
sebelum menyetel konten di file MainActivity.kt
.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
enableEdgeToEdge() // Add this line.
window.isNavigationBarContrastEnforced = false
super.onCreate(savedInstanceState)
setContent {... }
}
}
Impor untuk enableEdgeToEdge
adalah import androidx.activity.enableEdgeToEdge
. Dependensinya adalah AndroidX Activity 1.8.0 atau yang lebih baru.
Untuk ringkasan mendalam tentang cara menampilkan aplikasi dalam layar penuh agar kompatibel dengan versi lama dan cara menangani inset, lihat panduan berikut:
Hal ini mengakhiri bagian layar penuh dalam pembelajaran. Bagian berikutnya bersifat opsional dan membahas pertimbangan tampilan layar penuh lainnya yang mungkin berlaku untuk aplikasi Anda.
5. Opsional: Pertimbangan tampilan layar penuh tambahan
Menangani inset di seluruh arsitektur
Komponen
Anda mungkin melihat bahwa SociaLite tidak berubah setelah kita mengubah nilai SDK target. SociaLite dirancang dengan praktik terbaik sehingga menangani perubahan platform ini dapat dilakukan dengan mudah. Praktik terbaik mencakup hal berikut:
- Menggunakan komponen Desain Material 3 (
androidx.compose.material3
), likeTopAppBar
,BottomAppBar
, danNavigationBar
karena otomatis menerapkan inset. - Jika aplikasi Anda menggunakan komponen Material 2 (
androidx.compose.material
) di Compose, komponen tersebut tidak otomatis menangani inset sendiri. Namun, Anda dapat memperoleh akses ke inset dan menerapkannya secara manual. Diandroidx.compose.material 1.6.0
dan yang lebih baru, gunakan parameterwindowInsets
untuk menerapkan inset secara manual bagiBottomAppBar
,TopAppBar
,BottomNavigation
, danNavigationRail
. Demikian pula, gunakan parametercontentWindowInsets
untukScaffold
. Jika tidak, terapkan inset secara manual sebagai padding. - Jika aplikasi Anda menggunakan komponen View dan Material (
com.google.android.material
), sebagian besar Komponen Material berbasis View (sepertiBottomNavigationView
,BottomAppBar
,NavigationRailView
, danNavigationView
) menangani inset sehingga Anda tidak perlu melakukan apa pun. Namun, Anda perlu menambahkanandroid:fitsSystemWindows="true"
jika menggunakanAppBarLayout
. - Jika Aplikasi Anda menggunakan View dan
BottomSheet
,SideSheet
, atau kontainer kustom, terapkan padding menggunakanViewCompat.setOnApplyWindowInsetsListener
. UntukRecyclerView
, terapkan padding menggunakan pemroses ini dan juga tambahkanclipToPadding="false"
. - Gunakan
Scaffold
(atauNavigationSuiteScaffold
atauListDetailPaneScaffold
), bukanSurface
, untuk UI yang kompleks.Scaffold
memungkinkan Anda menempatkanTopAppBar
,BottomAppBar
,NavigationBar
, danNavigationRail
dengan mudah.
Men-scroll konten
Aplikasi Anda mungkin berisi daftar dan item terakhir dari daftar tersebut mungkin tertutup oleh menu navigasi sistem dengan perubahan Android 15.
Menampilkan item terakhir dalam daftar yang tertutup oleh navigasi tiga tombol.
Men-scroll konten dengan Compose
Di Compose, gunakan contentPadding LazyColumn
untuk menambahkan ruang ke item terakhir kecuali jika Anda menggunakan TextField
:
Scaffold { innerPadding ->
LazyColumn(
contentPadding = innerPadding
) {
// Content that does not contain TextField
}
}
Menampilkan item terakhir dalam daftar yang tidak tertutup oleh navigasi tiga tombol.
Untuk TextField
, gunakan Spacer
untuk menggambar TextField
terakhir di LazyColumn
. Untuk informasi selengkapnya, lihat Pemakaian inset.
LazyColumn(
Modifier.imePadding()
) {
// Content with TextField
item {
Spacer(
Modifier.windowInsetsBottomHeight(
WindowInsets.systemBars
)
)
}
}
Men-scroll konten dengan View
Untuk RecyclerView
atau NestedScrollView
, tambahkan android:clipToPadding="false"
.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layoutManager="LinearLayoutManager" />
Berikan padding kiri, kanan dan bawah dari inset jendela menggunakan setOnApplyWindowInsetsListener
:
ViewCompat.setOnApplyWindowInsetsListener(binding.recycler) { v, insets ->
val i = insets.getInsets(
WindowInsetsCompat.Type.systemBars() + WindowInsetsCompat.Type.displayCutout()
)
v.updatePadding(
left = i.left,
right = i.right,
bottom = i.bottom + bottomPadding,
)
WindowInsetsCompat.CONSUMED
}
Menggunakan LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
Sebelum menargetkan SDK 35, SociaLite tampak seperti ini dalam mode lanskap dengan kotak putih besar di tepi kiri untuk memperhitungkan potongan kamera. Pada navigasi tiga tombol, tombol berada di sisi kanan.
Setelah menargetkan SDK 35, SociaLite akan tampak seperti ini dan tidak lagi ada kotak putih besar di tepi kiri untuk memperhitungkan potongan kamera. Untuk memperoleh efek ini, Android otomatis menetapkan LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS.
Bergantung pada aplikasi, Anda mungkin ingin menangani inset di sini.
Untuk melakukannya di SociaLite, ikuti langkah-langkah berikut:
- Di file
ui/ContactRow.kt
, temukan composable Baris. - Ubah padding untuk memperhitungkan potongan layar.
@Composable
fun ChatRow(
chat: ChatDetail,
onClick: (() -> Unit)?,
modifier: Modifier = Modifier,
) {
// Add layoutDirection, displayCutout, startPadding, and endPadding.
val layoutDirection = LocalLayoutDirection.current
val displayCutout = WindowInsets.displayCutout.asPaddingValues()
val startPadding = displayCutout.calculateStartPadding(layoutDirection)
val endPadding = displayCutout.calculateEndPadding(layoutDirection)
Row(
modifier = modifier
...
// .padding(16.dp) // Remove this line.
// Add this block:
.padding(
PaddingValues(
top = 16.dp,
bottom = 16.dp,
// Ensure content is not occluded by display cutouts
// when rotating the device.
start = startPadding.coerceAtLeast(16.dp),
end = endPadding.coerceAtLeast(16.dp)
)
),
...
) { ... }
Setelah menangani potongan layar, SociaLite akan tampak seperti ini:
Anda dapat menguji berbagai konfigurasi potongan layar pada layar Opsi developer di bagian Potongan layar.
Jika aplikasi Anda memiliki jendela tidak mengambang (misalnya, Aktivitas) yang menggunakan LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
, LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
, atau LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
, Android akan menginterpretasikan mode potongan ini ke LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
mulai Android 15 Beta 2. Sebelumnya, di Android 15 Beta 1, aplikasi Anda akan error.
Kolom teks juga merupakan kolom sistem
Kolom teks juga merupakan kolom sistem karena mendeskripsikan dekorasi jendela UI sistem dari jendela freeform, seperti kolom judul atas. Anda dapat melihat kolom teks dalam emulator desktop di Android Studio. Pada screenshot berikut, kolom teks berada di bagian atas aplikasi.
Di Compose, jika Anda menggunakan PaddingValues
Scaffold, safeContent
, safeDrawing
, atau WindowInsets.systemBars
bawaan, aplikasi Anda akan ditampilkan seperti yang diharapkan. Namun, jika Anda menangani inset dengan statusBar
, konten aplikasi Anda mungkin tidak ditampilkan seperti yang diharapkan karena status bar tidak memperhitungkan kolom teks.
Di View, jika Anda menangani inset secara manual dengan WindowInsetsCompat.systemBars
, aplikasi Anda akan ditampilkan seperti yang diharapkan. Jika Anda menangani inset secara manual dengan WindowInsetsCompat.statusBars
, aplikasi Anda mungkin tidak ditampilkan seperti yang diharapkan karena status bar bukan kolom teks.
Aplikasi dalam mode imersif
Layar dalam mode imersif sebagian besar tidak terpengaruh oleh penerapan layar penuh Android 15, karena aplikasi imersif sudah menerapkan layar penuh.
Melindungi kolom sistem
Anda mungkin ingin aplikasi Anda memiliki panel transparan untuk navigasi gestur, tetapi panel transparan atau buram untuk navigasi tiga tombol.
Di Android 15, navigasi tiga tombol transparan merupakan setelan default karena platform menetapkan properti window.isNavigationBarContrastEnforced
ke true
. Navigasi gestur tetap transparan.
Navigasi tiga tombol transparan secara default. |
Secara umum, navigasi tiga tombol yang transparan sudah cukup. Namun, dalam beberapa kasus, aplikasi Anda mungkin memerlukan navigasi tiga tombol yang buram. Pertama, tetapkan properti window.isNavigationBarContrastEnforced
ke false
. Lalu, gunakan WindowInsetsCompat.tappableElement
untuk View atau WindowInsets.tappableElement
untuk Compose. Jika nilainya 0, pengguna sedang menggunakan navigasi gestur. Jika tidak, pengguna menggunakan navigasi tiga tombol. Jika pengguna menggunakan navigasi tiga tombol, buat tampilan atau kotak di belakang menu navigasi. Contoh Compose akan terlihat seperti ini:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
window.isNavigationBarContrastEnforced = false
MyTheme {
Surface(...) {
MyContent(...)
ProtectNavigationBar()
}
}
}
}
}
// Use only if required.
@Composable
fun ProtectNavigationBar(modifier: Modifier = Modifier) {
val density = LocalDensity.current
val tappableElement = WindowInsets.tappableElement
val bottomPixels = tappableElement.getBottom(density)
val usingTappableBars = remember(bottomPixels) {
bottomPixels != 0
}
val barHeight = remember(bottomPixels) {
tappableElement.asPaddingValues(density).calculateBottomPadding()
}
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Bottom
) {
if (usingTappableBars) {
Box(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.fillMaxWidth()
.height(barHeight)
)
}
}
}
Navigasi tiga tombol buram |
6. Meninjau kode solusi
Metode onCreate
file MainActivity.kt
akan terlihat seperti ini:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
enableEdgeToEdge()
window.isNavigationBarContrastEnforced = false
super.onCreate(savedInstanceState)
setContent {
Main(
shortcutParams = extractShortcutParams(intent),
)
}
}
}
Composable ChatContent
dalam file ChatScreen.kt
seharusnya menangani inset:
private fun ChatContent(...) {
...
Scaffold(...) { innerPadding ->
Column {
...
InputBar(
input = input,
onInputChanged = onInputChanged,
onSendClick = onSendClick,
onCameraClick = onCameraClick,
onPhotoPickerClick = onPhotoPickerClick,
contentPadding = innerPadding.copy(
layoutDirection, top = 0.dp
),
sendEnabled = sendEnabled,
modifier = Modifier
.fillMaxWidth()
.windowInsetsPadding(
WindowInsets.ime.exclude(WindowInsets.navigationBars)
),
)
}
}
}
Kode solusi tersedia di cabang utama. Jika Anda sudah mendownload SociaLite:
git checkout main
Jika belum, Anda dapat mendownload kode lagi untuk melihat cabang utama baik secara langsung atau melalui git:
git clone git@github.com:android/socialite.git