WebView mengelola perataan konten menggunakan dua area pandang: area pandang tata letak (ukuran halaman) dan area pandang visual (bagian halaman yang benar-benar dilihat pengguna). Meskipun area pandang tata letak umumnya statis, area pandang visual berubah secara dinamis saat pengguna memperbesar, men-scroll, atau saat elemen UI sistem (seperti keyboard virtual) muncul.
Kompatibilitas fitur
Dukungan WebView untuk inset jendela telah berkembang seiring waktu untuk menyelaraskan perilaku konten web dengan ekspektasi aplikasi Android native:
| Milestone | Fitur ditambahkan | Cakupan |
|---|---|---|
| M136 | Dukungan displayCutout() dan systemBars() melalui safe-area-insets CSS. |
Hanya WebView layar penuh. |
| M139 | Dukungan ime() (editor metode input, yang merupakan keyboard) melalui pengubahan ukuran area pandang visual. |
Semua WebView. |
| M144 | Dukungan displayCutout() dan systemBars(). |
Semua WebView (terlepas dari status layar penuh). |
Untuk informasi selengkapnya, lihat WindowInsetsCompat.
Mekanisme inti
WebView menangani inset melalui dua mekanisme utama:
Area aman (
displayCutout,systemBars): WebView meneruskan dimensi ini ke konten web melalui variabel safe-area-inset-* CSS. Hal ini memungkinkan developer mencegah elemen interaktif mereka sendiri (seperti menu navigasi) terhalang oleh notch atau status bar.Pengubahan ukuran area pandang visual menggunakan editor metode input (IME): Mulai M139, editor metode input (IME) langsung mengubah ukuran area pandang visual. Mekanisme pengubahan ukuran ini juga didasarkan pada persimpangan WebView-Jendela. Misalnya, dalam mode multitasking Android, jika bagian bawah WebView meluas 200 dp di bawah bagian bawah jendela, area pandang visual akan berukuran 200 dp lebih kecil daripada ukuran WebView. Pengubahan ukuran area pandang visual ini (untuk IME dan perpotongan Jendela WebView) hanya diterapkan ke bagian bawah WebView. Mekanisme ini tidak mendukung pengubahan ukuran untuk tumpang-tindih kiri, kanan, atau atas. Artinya, keyboard terpasang yang muncul di tepi tersebut tidak memicu pengubahan ukuran area pandang visual.
Sebelumnya, area pandang visual tetap, sering kali menyembunyikan kolom input di belakang keyboard. Dengan mengubah ukuran area pandang, bagian halaman yang terlihat akan dapat di-scroll secara default, sehingga pengguna dapat menjangkau konten yang tersembunyi.
Logika batas dan tumpang-tindih
WebView hanya akan menerima nilai inset bukan nol jika elemen UI sistem (panel, potongan layar, atau keyboard) tumpang-tindih langsung dengan batas layar WebView. Jika WebView tidak tumpang-tindih dengan elemen UI ini (misalnya, jika WebView berada di tengah layar dan tidak menyentuh kolom sistem), WebView akan menerima inset tersebut sebagai nol.
Untuk mengganti logika default ini dan memberikan dimensi sistem lengkap ke konten web terlepas dari tumpang-tindih, gunakan metode setOnApplyWindowInsetsListener dan tampilkan objek windowInsets asli yang tidak diubah dari pemroses. Memberikan dimensi sistem yang lengkap
dapat membantu memastikan konsistensi desain dengan memungkinkan konten web selaras dengan
hardware perangkat, terlepas dari posisi WebView saat ini. Hal ini memastikan
transisi yang lancar saat WebView berpindah atau diperluas untuk menyentuh tepi layar.
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(myWebView) { _, windowInsets -> // By returning the original windowInsets object, we override the default // behavior that zeroes out system insets (like system bars or display // cutouts) when they don't directly overlap the WebView's screen bounds. windowInsets }
Java
ViewCompat.setOnApplyWindowInsetsListener(myWebView, (v, windowInsets) -> { // By returning the original windowInsets object, we override the default // behavior that zeroes out system insets (like system bars or display // cutouts) when they don't directly overlap the WebView's screen bounds. return windowInsets; });
Mengelola peristiwa pengubahan ukuran
Karena visibilitas keyboard kini memicu pengubahan ukuran area pandang visual, kode web mungkin akan melihat peristiwa pengubahan ukuran yang lebih sering. Developer harus memastikan kode mereka tidak bereaksi terhadap peristiwa pengubahan ukuran ini dengan menghapus fokus elemen. Tindakan ini akan membuat loop kehilangan fokus dan penutupan keyboard yang mencegah input pengguna:
- Pengguna berfokus pada elemen input.
- Keyboard muncul, yang memicu peristiwa pengubahan ukuran.
- Kode situs menghapus fokus sebagai respons terhadap pengubahan ukuran.
- Keyboard disembunyikan karena fokus hilang.
Untuk mengurangi perilaku ini, tinjau pemroses sisi web untuk memastikan bahwa perubahan area pandang tidak secara tidak sengaja memicu fungsi JavaScript blur() atau perilaku penghapusan fokus.
Menerapkan penanganan inset
Setelan default WebView berfungsi secara otomatis untuk sebagian besar aplikasi. Namun, jika
aplikasi Anda menggunakan tata letak kustom (misalnya, jika Anda menambahkan padding sendiri untuk memperhitungkan
status bar atau keyboard), Anda dapat menggunakan pendekatan berikut untuk meningkatkan cara
konten web dan UI native bekerja sama. Jika UI native Anda menerapkan padding
ke penampung berdasarkan WindowInsets, Anda harus mengelola inset ini
dengan benar sebelum mencapai WebView untuk menghindari padding ganda.
Padding ganda adalah situasi saat tata letak native dan konten web menerapkan dimensi inset yang sama, sehingga menghasilkan spasi yang berlebihan. Misalnya, bayangkan ponsel dengan status bar 40 px. Tampilan native dan WebView melihat inset 40 px. Keduanya menambahkan padding 40 piksel, sehingga pengguna melihat celah 80 piksel di bagian atas.
Pendekatan Zeroing
Untuk mencegah padding ganda, Anda harus memastikan bahwa setelah tampilan native menggunakan
dimensi inset untuk padding, Anda mereset dimensi tersebut ke nol menggunakan
Insets.NONE pada objek WindowInsets baru sebelum meneruskan objek yang diubah
ke hierarki tampilan ke WebView.
Saat menerapkan padding ke tampilan induk, Anda biasanya harus menggunakan pendekatan penol-an
dengan menetapkan Insets.NONE, bukan WindowInsetsCompat.CONSUMED.
Menampilkan WindowInsetsCompat.CONSUMED mungkin berfungsi dalam situasi tertentu.
Namun, hal ini dapat mengalami masalah jika pengendali aplikasi Anda mengubah inset atau menambahkan padding-nya sendiri. Pendekatan penihilan tidak memiliki batasan ini.
Menghindari padding hantu dengan mengosongkan inset
Jika Anda menggunakan inset saat aplikasi sebelumnya telah meneruskan inset yang tidak digunakan, atau jika inset berubah (seperti keyboard yang disembunyikan), penggunaan inset tersebut akan mencegah WebView menerima notifikasi update yang diperlukan. Hal ini dapat menyebabkan WebView mempertahankan padding hantu dari status sebelumnya (misalnya, mempertahankan padding keyboard setelah keyboard disembunyikan).
Contoh berikut menunjukkan interaksi yang rusak antara aplikasi dan WebView:
- Status awal: Aplikasi awalnya meneruskan inset yang tidak digunakan (misalnya,
displayCutout()atausystemBars()) ke WebView, yang secara internal menerapkan padding ke konten web. - Perubahan status dan error: Jika aplikasi berubah status (misalnya, keyboard disembunyikan) dan aplikasi memilih untuk menangani inset yang dihasilkan dengan
menampilkan
WindowInsetsCompat.CONSUMED. - Notifikasi diblokir: Menggunakan inset akan mencegah sistem Android mengirimkan notifikasi update yang diperlukan ke hierarki tampilan ke WebView.
- Padding hantu: Karena WebView tidak menerima update, WebView akan mempertahankan padding dari status sebelumnya, sehingga menyebabkan padding hantu (misalnya, mempertahankan padding keyboard setelah keyboard disembunyikan).
Sebagai gantinya, gunakan WindowInsetsCompat.Builder untuk menetapkan jenis yang ditangani ke
nol sebelum meneruskan objek ke tampilan turunan. Hal ini memberi tahu WebView bahwa
inset tertentu tersebut telah diperhitungkan saat mengaktifkan
notifikasi untuk melanjutkan hierarki tampilan.
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, windowInsets -> // 1. Identify the inset types you want to handle natively val types = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() // 2. Extract the dimensions and apply them as padding to the native container val insets = windowInsets.getInsets(types) view.setPadding(insets.left, insets.top, insets.right, insets.bottom) // 3. Return a new WindowInsets object with the handled types set to NONE (zeroed). // This informs the WebView that these areas are already padded, preventing // double-padding while still allowing the WebView to update its internal state. WindowInsetsCompat.Builder(windowInsets) .setInsets(types, Insets.NONE) .build() }
Java
ViewCompat.setOnApplyWindowInsetsListener(rootView, (view, windowInsets) -> { // 1. Identify the inset types you want to handle natively int types = WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(); // 2. Extract the dimensions and apply them as padding to the native container Insets insets = windowInsets.getInsets(types); rootView.setPadding(insets.left, insets.top, insets.right, insets.bottom); // 3. Return a new Insets object with the handled types set to NONE (zeroed). // This informs the WebView that these areas are already padded, preventing // double-padding while still allowing the WebView to update its internal // state. return new WindowInsetsCompat.Builder(windowInsets) .setInsets(types, Insets.NONE) .build(); });
Cara menonaktifkan setelan ini
Untuk menonaktifkan perilaku modern ini dan kembali ke penanganan area pandang lama, lakukan hal berikut:
Mengintersepsi inset: Gunakan
setOnApplyWindowInsetsListeneratau gantionApplyWindowInsetsdi subclassWebView.Hapus inset: Menampilkan kumpulan inset yang digunakan (misalnya,
WindowInsetsCompat.CONSUMED) dari awal. Tindakan ini mencegah notifikasi inset disebarkan ke WebView sepenuhnya, sehingga secara efektif menonaktifkan pengubahan ukuran area pandang modern dan memaksa WebView mempertahankan ukuran area pandang visual awalnya.