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, men-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 | displayCutout() dan systemBars() melalui CSS safe-area-insets. |
Hanya WebView layar penuh. |
| M139 | ime() (editor metode input, yaitu 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 poni atau status bar.Pengubahan ukuran area tampilan visual menggunakan editor metode input (IME): Mulai M139, editor metode input (IME) secara langsung mengubah ukuran area tampilan visual. Mekanisme pengubahan ukuran ini juga didasarkan pada persimpangan WebView-Window. Misalnya, dalam mode multitasking Android, jika bagian bawah WebView meluas 200dp di bawah bagian bawah jendela, viewport visual berukuran 200dp lebih kecil daripada ukuran WebView. Pengubahan ukuran area pandang visual ini (untuk IME dan persimpangan WebView-Window) hanya diterapkan di bagian bawah WebView. Mekanisme ini tidak mendukung pengubahan ukuran untuk tumpang-tindih kiri, kanan, atau atas. Artinya, keyboard yang terpasang di tepi tersebut tidak memicu pengubahan ukuran area pandang visual.
Sebelumnya, area pandang visual tetap tetap, sering kali menyembunyikan kolom input di balik keyboard. Dengan mengubah ukuran viewport, bagian halaman yang terlihat akan dapat di-scroll secara default, sehingga pengguna dapat mengakses konten yang terhalang.
Logika batas dan tumpang-tindih
WebView hanya boleh menerima nilai inset non-nol saat 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 dipusatkan di layar dan tidak menyentuh kolom sistem), WebView harus menerima inset tersebut sebagai nol.
Untuk mengganti logika default ini dan memberikan dimensi sistem lengkap
pada konten web terlepas dari tumpang-tindih, gunakan metode
setOnApplyWindowInsetsListener dan tampilkan objek windowInsets asli yang tidak dimodifikasi
dari pemroses. Menyediakan 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 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 pemroses sisi web untuk memastikan perubahan area tampilan 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 kerja bersama konten web dan UI native. Jika UI native Anda menerapkan padding
ke penampung berdasarkan WindowInsets, Anda harus mengelola inset ini
dengan benar sebelum mencapai WebView untuk menghindari padding ganda.
Pengisihan ganda adalah situasi saat tata letak native dan konten web menerapkan dimensi inset yang sama, sehingga menghasilkan penspasian yang berlebihan. Misalnya, bayangkan ponsel dengan status bar 40 px. Tampilan native dan WebView melihat inset 40 px. Keduanya menambahkan padding 40 px, sehingga pengguna melihat celah 80 px 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 WebView.
Saat menerapkan padding ke tampilan induk, Anda umumnya harus menggunakan pendekatan
pengurangan dengan menyetel Insets.NONE, bukan WindowInsetsCompat.CONSUMED.
Mengembalikan WindowInsetsCompat.CONSUMED mungkin berfungsi dalam situasi tertentu.
Namun, masalah dapat terjadi jika handler aplikasi Anda mengubah inset atau menambahkan padding-nya sendiri. Pendekatan peniadaan tidak memiliki batasan ini.
Menghindari padding hantu dengan menyetel inset ke nol
Jika Anda menggunakan inset saat aplikasi sebelumnya telah meneruskan inset yang tidak digunakan, atau jika inset berubah (seperti keyboard yang disembunyikan), menggunakan inset 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 terganggu 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 mencegah sistem Android mengirim notifikasi update yang diperlukan ke hierarki tampilan hingga ke WebView.
- Padding hantu: Karena WebView tidak menerima update, WebView mempertahankan padding dari status sebelumnya, sehingga menyebabkan padding hantu (misalnya, mempertahankan padding keyboard setelah keyboard disembunyikan).
Sebagai gantinya, gunakan WindowInsetsCompat.Builder untuk menyetel 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 terus turun dalam 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 menyisih
Untuk menonaktifkan perilaku modern ini dan kembali ke penanganan area tampilan lama, lakukan tindakan berikut:
Inset pencegat: Gunakan
setOnApplyWindowInsetsListeneratau gantionApplyWindowInsetsdi subclassWebView.Inset yang jelas: Menampilkan set inset yang digunakan (misalnya,
WindowInsetsCompat.CONSUMED) dari awal. Tindakan ini mencegah notifikasi inset berpropagasi ke WebView sepenuhnya, sehingga secara efektif menonaktifkan pengubahan ukuran viewport modern dan memaksa WebView mempertahankan ukuran viewport visual awalnya.