WebView, içerik hizalamasını iki görüntü alanı kullanarak yönetir: düzen görüntü alanı (sayfa boyutu) ve görsel görüntü alanı (sayfanın kullanıcının gerçekten gördüğü kısmı). Düzen görüntü alanı genellikle statik olsa da görsel görüntü alanı, kullanıcılar yakınlaştırdığında, kaydırdığında veya sistem kullanıcı arayüzü öğeleri (ör. yazılım klavyesi) göründüğünde dinamik olarak değişir.
Özellik uyumluluğu
Pencere ekleri için WebView desteği, web içeriği davranışını yerel Android uygulama beklentileriyle uyumlu hale getirmek için zaman içinde gelişti:
| Milestone | Özellik eklendi | Kapsam |
|---|---|---|
| M136 | CSS safe-area-insets aracılığıyla displayCutout() ve systemBars() desteği. |
Yalnızca tam ekran WebView'lar. |
| M139 | Görsel görüntü alanı yeniden boyutlandırma yoluyla ime() (giriş yöntemi düzenleyici, yani klavye) desteği. |
Tüm Web Görünümleri. |
| M144 | displayCutout() ve systemBars() desteği. |
Tüm Web Görünümleri (tam ekran durumundan bağımsız olarak). |
Daha fazla bilgi için WindowInsetsCompat başlıklı makaleyi inceleyin.
Temel mekanikler
WebView, iç boşlukları iki temel mekanizma aracılığıyla işler:
Güvenli alanlar (
displayCutout,systemBars): WebView, bu boyutları CSS safe-area-inset-* değişkenleri aracılığıyla web içeriğine yönlendirir. Bu sayede geliştiriciler, kendi etkileşimli öğelerinin (gezinme çubukları gibi) çentikler veya durum çubukları tarafından gizlenmesini önleyebilir.Giriş yöntemi düzenleyici (IME) kullanılarak görsel görüntü alanının yeniden boyutlandırılması: M139'dan itibaren giriş yöntemi düzenleyici (IME), görsel görüntü alanını doğrudan yeniden boyutlandırır. Bu yeniden boyutlandırma mekanizması da WebView-Pencere kesişimini temel alır. Örneğin, Android çoklu görev modunda bir WebView'un alt kısmı pencerenin alt kısmının 200 dp altına uzanıyorsa görsel görüntü alanı, WebView'un boyutundan 200 dp daha küçüktür. Bu görsel görüntü alanı yeniden boyutlandırma (hem IME hem de WebView-Pencere kesişimi için) yalnızca WebView'un alt kısmına uygulanır. Bu mekanizma; sol, sağ veya üst çakışma için yeniden boyutlandırmayı desteklemez. Bu, bu kenarlarda görünen sabitlenmiş klavyelerin görsel görüntü alanı yeniden boyutlandırmasını tetiklemediği anlamına gelir.
Daha önce görsel görüntü alanı sabit kalıyordu ve genellikle giriş alanlarını klavyenin arkasında gizliyordu. Görüntü alanını yeniden boyutlandırarak sayfanın görünür kısmı varsayılan olarak kaydırılabilir hale gelir ve kullanıcıların gizli içeriğe ulaşabilmesi sağlanır.
Sınırlar ve çakışma mantığı
WebView, yalnızca sistem kullanıcı arayüzü öğeleri (çubuklar, ekran kesikleri veya klavye) WebView'un ekran sınırlarıyla doğrudan çakıştığında sıfır olmayan iç değerler almalıdır. Bir WebView bu kullanıcı arayüzü öğeleriyle çakışmıyorsa (ör. WebView ekranda ortalanmışsa ve sistem çubuklarına dokunmuyorsa) bu iç kısımları sıfır olarak almalıdır.
Bu varsayılan mantığı geçersiz kılmak ve çakışmadan bağımsız olarak web içeriğine tam sistem boyutlarını sağlamak için setOnApplyWindowInsetsListener yöntemini kullanın ve dinleyiciden orijinal, değiştirilmemiş windowInsets nesnesini döndürün. Sistem boyutlarının tamamını sağlamak, web içeriğinin WebView'un mevcut konumundan bağımsız olarak cihaz donanımıyla uyumlu olmasını sağlayarak tasarım tutarlılığını korumaya yardımcı olabilir. Bu sayede, WebView ekran kenarlarına dokunacak şekilde hareket ederken veya genişlerken sorunsuz bir geçiş sağlanır.
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; });
Yeniden boyutlandırma etkinliklerini yönetme
Klavye görünürlüğü artık görsel görüntü alanının yeniden boyutlandırılmasını tetiklediğinden web kodu, daha sık yeniden boyutlandırma etkinlikleri görebilir. Geliştiriciler, kodlarının öğe odağını temizleyerek bu yeniden boyutlandırma etkinliklerine tepki vermediğinden emin olmalıdır. Bunu yaptığınızda, odak kaybı ve klavyenin kapatılmasıyla ilgili bir döngü oluşur ve kullanıcı girişi engellenir:
- Kullanıcı bir giriş öğesine odaklandığında
- Klavye görünür ve yeniden boyutlandırma etkinliği tetiklenir.
- Web sitesinin kodu, yeniden boyutlandırmaya yanıt olarak odağı temizler.
- Odak kaybedildiği için klavye gizlenir.
Bu davranışı azaltmak için web tarafındaki dinleyicileri inceleyerek görüntü alanı değişikliklerinin blur() JavaScript işlevini veya odak temizleme davranışlarını istemeden tetiklemediğinden emin olun.
İç metin işlemeyi uygulama
WebView'un varsayılan ayarları çoğu uygulamada otomatik olarak çalışır. Ancak uygulamanız özel düzenler kullanıyorsa (örneğin, durum çubuğunu veya klavyeyi hesaba katmak için kendi dolgunuzu eklerseniz) web içeriği ile yerel kullanıcı arayüzünün birlikte çalışma şeklini iyileştirmek için aşağıdaki yaklaşımları kullanabilirsiniz. Yerel kullanıcı arayüzünüz, WindowInsets'ye göre bir kapsayıcıya dolgu uyguluyorsa çift dolguyu önlemek için bu iç kısımları WebView'a ulaşmadan önce doğru şekilde yönetmeniz gerekir.
Çift dolgu, doğal düzen ve web içeriğinin aynı iç metin boyutlarını uygulayarak gereksiz boşluklara neden olduğu bir durumdur. Örneğin, 40 piksellik durum çubuğu olan bir telefon düşünün. Hem yerel görünüm hem de WebView, 40 piksellik içe yerleştirmeyi görür. Her ikisi de 40 piksellik dolgu ekler ve kullanıcı üstte 80 piksellik bir boşluk görür.
Sıfırlama yaklaşımı
Çift dolguyu önlemek için yerel görünüm, dolgu için içe yerleştirme boyutunu kullandıktan sonra yeni bir WindowInsets nesnesinde Insets.NONE kullanarak bu boyutu sıfırlamanız gerekir. Ardından, değiştirilen nesneyi görünüm hiyerarşisinden WebView'a iletebilirsiniz.
Bir üst görünüme dolgu uygularken genellikle WindowInsetsCompat.CONSUMED yerine Insets.NONE değerini ayarlayarak sıfırlama yaklaşımını kullanmanız gerekir.
WindowInsetsCompat.CONSUMED iade etmek bazı durumlarda işe yarayabilir.
Ancak uygulamanızın işleyicisi, iç kısımları değiştirirse veya kendi dolgusunu eklerse sorunlarla karşılaşabilir. Sıfırlama yaklaşımında bu sınırlamalar yoktur.
İç boşlukları sıfırlayarak hayalet dolguyu önleme
Uygulama daha önce kullanılmamış iç kısımları ilettiğinde iç kısımları kullanırsanız veya iç kısımlar değişirse (ör. klavyenin gizlenmesi) iç kısımların kullanılması, WebView'un gerekli güncelleme bildirimini almasını engeller. Bu durum, WebView'un önceki bir durumdan kalan hayalet dolguyu korumasına (örneğin, klavye gizlendikten sonra klavye dolgusunu korumasına) neden olabilir.
Aşağıdaki örnekte, uygulama ile WebView arasındaki etkileşimin bozulduğu gösterilmektedir:
- İlk durum: Uygulama başlangıçta tüketilmemiş iç boşlukları (ör.
displayCutout()veyasystemBars()) WebView'a iletir. WebView, web içeriğine dahili olarak dolgu uygular. - Durum değişikliği ve hata: Uygulama durum değiştirirse (ör. klavye gizlenirse) ve uygulama,
WindowInsetsCompat.CONSUMEDdeğerini döndürerek ortaya çıkan iç kısımları işlemeyi seçerse. - Bildirim engellendi: İç kısımların kullanılması, Android sisteminin gerekli güncelleme bildirimini görünüm hiyerarşisinden WebView'a göndermesini engeller.
- Hayalet dolgu: WebView güncellemeyi almadığı için önceki durumdaki dolguyu korur. Bu da hayalet dolguya neden olur (örneğin, klavye gizlendikten sonra klavye dolgusunu korur).
Bunun yerine, nesneyi çocuk ekranlarına iletmeden önce işlenen türleri sıfıra ayarlamak için WindowInsetsCompat.Builder kullanın. Bu, WebView'a söz konusu iç kısımların zaten hesaba katıldığını bildirir ve bildirimin görünüm hiyerarşisinde aşağı doğru devam etmesini sağlar.
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(); });
Devre dışı bırakma
Bu modern davranışları devre dışı bırakmak ve eski görüntü alanı işleme yöntemine dönmek için aşağıdakileri yapın:
İçerikleri kesme:
setOnApplyWindowInsetsListenerkullanın veya birWebViewalt sınıfındaonApplyWindowInsetsyöntemini geçersiz kılın.İç kısımları temizle: Kullanılan bir iç kısım grubunu (ör.
WindowInsetsCompat.CONSUMED) baştan itibaren döndürür. Bu işlem, iç metin bildiriminin WebView'a yayılmasını tamamen engeller. Böylece modern görüntü alanı yeniden boyutlandırma etkili bir şekilde devre dışı bırakılır ve WebView, ilk görsel görüntü alanı boyutunu korumaya zorlanır.