WebView zarządza wyrównaniem treści za pomocą 2 widocznych obszarów: widocznego obszaru układu (rozmiaru strony) i widocznego obszaru wizualnego (części strony, którą użytkownik faktycznie widzi). Podczas gdy widoczny obszar układu jest zwykle statyczny, widoczny obszar wizualny zmienia się dynamicznie, gdy użytkownicy powiększają, przewijają lub gdy pojawiają się elementy interfejsu systemu (takie jak klawiatura ekranowa).
Zgodność funkcji
Obsługa wstawek okna w komponencie WebView ewoluowała z czasem, aby dostosować zachowanie treści z internetu do oczekiwań natywnych aplikacji na Androida:
| Kamień milowy | Dodano funkcję | Zakres |
|---|---|---|
| M136 | Obsługa displayCutout() i systemBars() za pomocą właściwości CSS safe-area-insets. |
Tylko pełnoekranowe komponenty WebView. |
| M139 | Obsługa ime() (edytora metody wprowadzania, czyli klawiatury) przez zmianę rozmiaru widocznego obszaru. |
Wszystkie komponenty WebView. |
| M144 | Obsługa displayCutout() i systemBars(). |
Wszystkie komponenty WebView (niezależnie od stanu pełnego ekranu). |
Więcej informacji: WindowInsetsCompat.
Główna mechanika
WebView obsługuje wstawki za pomocą 2 głównych mechanizmów:
Bezpieczne obszary (
displayCutout,systemBars): WebView przekazuje te wymiary do treści z internetu za pomocą zmiennych CSS safe-area-inset-*. Dzięki temu deweloperzy mogą zapobiegać zasłanianiu własnych elementów interaktywnych (takich jak paski nawigacyjne) przez wycięcia lub paski stanu.Zmiana rozmiaru widocznego obszaru za pomocą edytora metody wprowadzania (IME): od wersji M139 edytor metody wprowadzania (IME) bezpośrednio zmienia rozmiar widocznego obszaru. Ten mechanizm zmiany rozmiaru również opiera się na przecięciu WebView i okna. Na przykład w trybie wielozadaniowym na Androidzie, jeśli dół komponentu WebView rozciąga się o 200 dp poniżej dolnej krawędzi okna, widoczny obszar jest o 200 dp mniejszy niż rozmiar komponentu WebView. Zmiana rozmiaru wizualnego obszaru wyświetlania (zarówno w przypadku edytora IME, jak i części wspólnej WebView i okna) jest stosowana tylko u dołu komponentu WebView. Ten mechanizm nie obsługuje zmiany rozmiaru w przypadku nakładania się po lewej, prawej lub u góry. Oznacza to, że zadokowane klawiatury, które pojawiają się na tych krawędziach, nie powodują zmiany rozmiaru widocznego obszaru.
Wcześniej widoczny obszar pozostawał stały, co często powodowało ukrywanie pól do wprowadzania danych za klawiaturą. Dzięki zmianie rozmiaru widocznego obszaru widoczna część strony staje się domyślnie przewijalna, co zapewnia użytkownikom dostęp do zasłoniętych treści.
Logika granic i nakładania się
Komponent WebView powinien otrzymywać niezerowe wartości wstawki tylko wtedy, gdy elementy interfejsu systemu (paski, wycięcia w ekranie lub klawiatura) bezpośrednio nakładają się na granice ekranu komponentu WebView. Jeśli komponent WebView nie nakłada się na te elementy interfejsu (np. jeśli jest wyśrodkowany na ekranie i nie dotyka pasków systemowych), powinien otrzymać te wstawki jako zero.
Aby zastąpić tę domyślną logikę i udostępnić treściom z internetu pełne wymiary systemu niezależnie od nakładania się, użyj metody setOnApplyWindowInsetsListener i zwróć oryginalny, niezmodyfikowany obiekt windowInsets z detektora. Podanie pełnych wymiarów systemu może pomóc w zapewnieniu spójności projektu, ponieważ umożliwia dopasowanie treści z internetu do sprzętu urządzenia niezależnie od bieżącej pozycji komponentu WebView. Zapewnia to płynne przejście, gdy komponent WebView przesuwa się lub rozszerza, aby dotknąć krawędzi ekranu.
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; });
Zarządzanie zdarzeniami zmiany rozmiaru
Ponieważ widoczność klawiatury powoduje teraz zmianę rozmiaru widocznego obszaru, kod internetowy może częściej wykrywać zdarzenia zmiany rozmiaru. Deweloperzy muszą zadbać o to, aby ich kod nie reagował na te zdarzenia zmiany rozmiaru przez usuwanie zaznaczenia elementu. Powoduje to pętlę utraty zaznaczenia i zamknięcia klawiatury, która uniemożliwia użytkownikowi wprowadzanie danych:
- użytkownik skupia się na elemencie wejściowym;
- Pojawia się klawiatura, co powoduje wywołanie zdarzenia zmiany rozmiaru.
- Kod witryny usuwa zaznaczenie w odpowiedzi na zmianę rozmiaru.
- Klawiatura jest ukryta, ponieważ utracono zaznaczenie.
Aby temu zapobiec, sprawdź detektory po stronie internetowej i upewnij się, że zmiany widocznego obszaru nie wywołują niezamierzenie funkcji JavaScriptu blur() ani zachowań związanych z czyszczeniem zaznaczenia.
Implementowanie obsługi wcięć
Domyślne ustawienia WebView działają automatycznie w większości aplikacji. Jeśli jednak aplikacja używa układów niestandardowych (np. dodajesz własne dopełnienie, aby uwzględnić pasek stanu lub klawiaturę), możesz użyć poniższych metod, aby poprawić współdziałanie treści internetowych i natywnego interfejsu użytkownika. Jeśli natywny interfejs użytkownika stosuje do kontenera dopełnienie na podstawie WindowInsets, musisz prawidłowo zarządzać tymi wstawkami, zanim dotrą do komponentu WebView, aby uniknąć podwójnego dopełnienia.
Podwójne dopełnienie to sytuacja, w której układ natywny i treści z internetu mają te same wymiary, co powoduje niepotrzebne odstępy. Załóżmy na przykład, że telefon ma pasek stanu o wysokości 40 pikseli. Zarówno widok natywny, jak i WebView widzą wstawkę 40 pikseli. Oba dodają 40 pikseli dopełnienia, co powoduje, że użytkownik widzi u góry odstęp o szerokości 80 pikseli.
Podejście zerowania
Aby zapobiec podwójnemu dopełnieniu, musisz upewnić się, że po użyciu przez widok natywny wymiaru wstawki do dopełnienia wymiar ten zostanie zresetowany do zera za pomocą Insets.NONE w nowym obiekcie WindowInsets, zanim zmodyfikowany obiekt zostanie przekazany w dół hierarchii widoków do WebView.
Podczas stosowania dopełnienia do widoku rodzica należy zwykle używać podejścia zerowania, ustawiając Insets.NONE zamiast WindowInsetsCompat.CONSUMED.
W niektórych sytuacjach może sprawdzić się zwrócenie wartości WindowInsetsCompat.CONSUMED.
Mogą jednak wystąpić problemy, jeśli moduł obsługi aplikacji zmieni wstawki lub doda własne dopełnienie. Metoda zerowania nie ma tych ograniczeń.
Unikanie dopełnienia widma przez wyzerowanie wcięć
Jeśli wykorzystasz wstawki, gdy aplikacja wcześniej przekazała niewykorzystane wstawki, lub jeśli wstawki ulegną zmianie (np. klawiatura zostanie ukryta), ich wykorzystanie uniemożliwi WebView otrzymanie niezbędnego powiadomienia o aktualizacji. Może to spowodować, że WebView zachowa dopełnienie z poprzedniego stanu (np. dopełnienie klawiatury po jej ukryciu).
Poniższy przykład pokazuje nieprawidłową interakcję między aplikacją a komponentem WebView:
- Stan początkowy: aplikacja początkowo przekazuje do WebView nieskonsumowane wstawki (np.
displayCutout()lubsystemBars()), które wewnętrznie stosują dopełnienie do treści z internetu. - Zmiana stanu i błąd: jeśli aplikacja zmieni stan (np. klawiatura zostanie ukryta) i zdecyduje się obsłużyć wynikowe wstawki, zwracając
WindowInsetsCompat.CONSUMED. - Zablokowane powiadomienie: wykorzystanie wstawek uniemożliwia systemowi Android wysłanie niezbędnego powiadomienia o aktualizacji w dół hierarchii widoków do komponentu WebView.
- Dopełnienie widma: ponieważ WebView nie otrzymuje aktualizacji, zachowuje dopełnienie z poprzedniego stanu, co powoduje dopełnienie widma (np. zachowanie dopełnienia klawiatury po jej ukryciu).
Zamiast tego użyj WindowInsetsCompat.Builder, aby ustawić obsługiwane typy na zero przed przekazaniem obiektu do widoków podrzędnych. Informuje to WebView, że te konkretne wstawki zostały już uwzględnione, i umożliwia powiadomieniu dalsze przechodzenie w dół hierarchii widoków.
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(); });
Jak zrezygnować
Aby wyłączyć te nowoczesne zachowania i powrócić do starszego sposobu obsługi widocznego obszaru, wykonaj te czynności:
Przechwytywanie wcięć: użyj
setOnApplyWindowInsetsListenerlub zastąponApplyWindowInsetsw podklasieWebView.Wyczyść wstawki: zwróć wykorzystany zestaw wstawek (np.
WindowInsetsCompat.CONSUMED) od początku. To działanie zapobiega propagowaniu powiadomienia o wstawce do komponentu WebView, co skutecznie wyłącza nowoczesną zmianę rozmiaru widocznego obszaru i wymusza zachowanie początkowego rozmiaru widocznego obszaru przez komponent WebView.