Menangani penerapan layar penuh di Android 15

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:

Aplikasi SociaLite dalam navigasi tiga tombol.

Aplikasi SociaLite dalam navigasi gestur.

SociaLite dengan navigasi tiga tombol

SociaLite dengan navigasi gestur

Aplikasi SociaLite di perangkat layar besar.

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

  1. 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
  1. Buka SociaLite di Android Studio dan jalankan aplikasi di perangkat atau emulator Android 15 Anda. Anda akan melihat layar yang tampak seperti berikut:

SociaLite dengan navigasi tiga tombol.

SociaLite dengan navigasi gestur.

Navigasi tiga tombol

Navigasi gestur

SociaLite di perangkat layar besar.

Perangkat layar besar

  1. Di halaman Chats, pilih salah satu percakapan, misalnya percakapan dengan anjing.

Pesan chat Dog dengan navigasi tiga tombol

Pesan chat Dog dengan navigasi gestur

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.

GIF aplikasi yang ditampilkan dalam 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

  1. 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
        ...
    }
...
}
  1. 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.

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.

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:

  1. 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.

  1. 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 navigasi tiga tombol dan banding dihapus.

Percakapan Dog dalam navigasi gestur.

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.

Percakapan Dog dalam navigasi gestur.

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:

  1. Buka file ui/chat/ChatScreen.kt, lalu cari composable ChatContent di sekitar baris 178, yang berisi UI untuk layar percakapan. ChatContent memanfaatkan Scaffold 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 padding Scaffold (parameter innerPadding). Tambahkan padding menggunakan innerPadding Scaffold ke InputBar.
  2. Temukan InputBar dalam ChatContent di dekat baris 214. Composable ini adalah composable kustom yang membuat UI bagi pengguna agar dapat menulis pesan. Pratinjaunya terlihat seperti ini:

PreviewInputBar.

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
            }
        }
    }
}
  1. Kembali ke InputBar dalam ChatContent dan ubah contentPadding 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.
    ...
 )
  1. Jalankan kembali aplikasi di perangkat Android 15.

Percakapan Dog dalam navigasi tiga tombol.

Percakapan Dog dalam navigasi gestur.

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.

  1. Untuk memperbaiki padding atas, buat salinan PaddingValues innerPadding, tetapkan padding atas ke 0.dp, dan teruskan salinan yang diubah ke contentPadding.
InputBar(
    ...
    contentPadding = innerPadding.copy(layoutDirection, top = 0.dp), //Add this line.
    // contentPadding = innerPadding, // Remove this line.
    ...
 )
  1. Jalankan kembali aplikasi di perangkat Android 15.

Percakapan Dog dalam navigasi tiga tombol.

Percakapan Dog dalam navigasi gestur.

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:

Men-scroll konten

Aplikasi Anda mungkin berisi daftar dan item terakhir dari daftar tersebut mungkin tertutup oleh menu navigasi sistem dengan perubahan Android 15.

Aplikasi dengan item daftar terakhir yang tertutup oleh navigasi tiga tombol.

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
    }
}

Aplikasi dengan item daftar terakhir yang tidak tertutup oleh navigasi tiga tombol.

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.

Aplikasi SociaLite dalam mode lanskap.

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. Aplikasi SociaLite dalam mode lanskap.

Bergantung pada aplikasi, Anda mungkin ingin menangani inset di sini.

Untuk melakukannya di SociaLite, ikuti langkah-langkah berikut:

  1. Di file ui/ContactRow.kt, temukan composable Baris.
  2. 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:

Aplikasi SociaLite dalam mode lanskap.

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.

Emulator menampilkan kolom teks.

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.

Aplikasi dalam navigasi tiga tombol.

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)
           )
       }
   }
}

Aplikasi dalam navigasi tiga tombol.

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