WebView mengelola perataan konten menggunakan dua area pandang: area pandang tata letak (ukuran halaman) dan area pandang visual (bagian halaman yang sebenarnya dilihat pengguna ). Meskipun area pandang tata letak umumnya statis, area pandang visual berubah secara dinamis saat pengguna melakukan zoom, scroll, atau saat elemen UI sistem (seperti keyboard software) muncul.
Kompatibilitas fitur
Dukungan WebView untuk inset jendela telah berkembang dari waktu ke waktu untuk menyelaraskan perilaku konten web dengan ekspektasi aplikasi Android native:
| Milestone | Fitur ditambahkan | Cakupan |
|---|---|---|
| M136 | Dukungan displayCutout() dan systemBars() melalui CSS safe-area-insets. |
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 mengetahui 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 CSS safe-area-inset-*. Hal ini memungkinkan developer mencegah elemen interaktif mereka sendiri (seperti panel navigasi) terhalang oleh takik atau status bar.Pengubahan ukuran area pandang visual menggunakan editor metode input (IME): Mulai M139, editor metode input (IME) mengubah ukuran area pandang visual secara langsung. Mekanisme pengubahan ukuran ini juga didasarkan pada persimpangan WebView-Window. Misalnya, dalam mode multitasking Android, jika bagian bawah WebView diperluas 200dp di bawah bagian bawah jendela, area pandang visual akan 200dp lebih kecil dari ukuran WebView. Pengubahan ukuran area pandang visual ini (untuk persimpangan IME dan WebView-Window) hanya diterapkan ke bagian bawah WebView. Mekanisme ini tidak mendukung pengubahan ukuran untuk tumpang-tindih kiri, kanan, atau atas. Artinya, keyboard yang ditempatkan di tepi tersebut tidak akan memicu pengubahan ukuran area pandang visual.
Sebelumnya, area pandang visual tetap diperbaiki, 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 terhalang.
Batas dan logika tumpang-tindih
WebView hanya boleh menerima nilai inset non-nol jika elemen UI sistem (status bar, takik layar, atau keyboard) tumpang-tindih secara langsung dengan batas layar WebView. Jika WebView tidak tumpang-tindih dengan elemen UI ini (misalnya, jika WebView berada di tengah layar dan tidak menyentuh status bar), WebView harus 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 listener. Menyediakan dimensi sistem 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 bergerak 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 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, memicu peristiwa pengubahan ukuran.
- Kode situs menghapus fokus sebagai respons terhadap pengubahan ukuran.
- Keyboard disembunyikan karena fokus hilang.
Untuk mengurangi perilaku ini, tinjau listener 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 ketika tata letak native dan konten web menerapkan dimensi inset yang sama, sehingga menghasilkan spasi yang berlebihan. Misalnya, bayangkan ponsel dengan status bar 40 piksel. Tampilan native dan WebView melihat inset 40 piksel. 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 umumnya harus menggunakan pendekatan zeroing dengan menetapkan Insets.NONE, bukan WindowInsetsCompat.CONSUMED.
Menampilkan WindowInsetsCompat.CONSUMED mungkin berfungsi dalam situasi tertentu.
Namun, hal ini dapat menyebabkan masalah jika pengendali aplikasi Anda mengubah inset atau menambahkan paddingnya sendiri. Pendekatan zeroing tidak memiliki batasan ini.
Menghindari padding ghost dengan inset zeroing
Jika Anda menggunakan inset saat aplikasi sebelumnya meneruskan inset yang tidak digunakan, atau jika inset berubah (seperti keyboard yang disembunyikan), menggunakannya akan mencegah WebView menerima notifikasi update yang diperlukan. Hal ini dapat menyebabkan WebView mempertahankan padding ghost 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 mengubah 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 ghost: Karena WebView tidak menerima update, WebView mempertahankan padding dari status sebelumnya, sehingga menyebabkan padding ghost (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 sekaligus memungkinkan notifikasi untuk terus turun ke 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:
Mencegat inset: Gunakan
setOnApplyWindowInsetsListeneratau gantionApplyWindowInsetsdi subclassWebView.Hapus inset: Tampilkan 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 untuk mempertahankan ukuran area pandang visual awalnya.