WebView'da pencere iç kısımlarını anlama

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ı (kullanıcının gerçekten gördüğü sayfa bölümü). Düzen görüntü alanı genellikle statik olsa da kullanıcılar yakınlaştırma veya kaydırma yaptığında ya da sistem kullanıcı arayüzü öğeleri (ör. yazılım klavyesi) göründüğünde görsel görüntü alanı dinamik olarak değişir.

Özellik uyumluluğu

Pencere yerleştirmeleri için WebView desteği, web içeriği davranışını yerel Android uygulaması beklentileriyle uyumlu hale getirmek üzere zaman içinde gelişmiştir:

Milestone Özellik eklendi Kapsam
M136 displayCutout() ve systemBars(), CSS safe-area-insets aracılığıyla desteklenir. Yalnızca tam ekran WebView'lar.
M139 Görsel görüntü alanı yeniden boyutlandırma yoluyla ime() (klavye olan giriş yöntemi düzenleyici) desteği. Tüm WebView'lar.
M144 displayCutout() ve systemBars() desteği. Tüm WebView'lar (tam ekran durumundan bağımsız olarak).

Daha fazla bilgi için WindowInsetsCompat sayfasına bakın.

Temel mekanikler

WebView, ekleri 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 iletir. Bu sayede geliştiriciler, kendi etkileşimli öğelerinin (ör. gezinme çubukları) çentikler veya durum çubukları tarafından kapatılmasını önleyebilir.

  • Giriş yöntemi düzenleyici (IME) kullanılarak görsel görünüm alanı yeniden boyutlandırılıyor: M139'dan itibaren giriş yöntemi düzenleyici (IME), görsel görünüm alanını doğrudan yeniden boyutlandırıyor. Bu yeniden boyutlandırma mekanizması da WebView-Window kesişimine dayanır. Örneğin, Android'de çoklu görev modunda bir WebView'un alt kısmı pencerenin alt kısmından 200 dp aşağıya 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-Window kesişimi için) yalnızca WebView'ın alt kısmına uygulanır. Bu mekanizma, sol, sağ veya üst üste gelme için yeniden boyutlandırmayı desteklemez. Bu, bu kenarlarda görünen yerleştirilmiş klavyelerin görsel görüntü alanı yeniden boyutlandırmasını tetiklemeyeceği anlamına gelir.

Daha önce görsel görüntü alanı sabit kalıyor ve giriş alanlarını klavyenin arkasında gizliyordu. Görüntü alanı yeniden boyutlandırıldığında, sayfanın görünür kısmı varsayılan olarak kaydırılabilir hale gelir. Böylece kullanıcılar, görünmeyen içeriğe ulaşabilir.

Sınırlar ve çakışma mantığı

WebView, yalnızca sistem kullanıcı arayüzü öğeleri (çubuklar, ekran kesikleri veya klavye) doğrudan WebView'un ekran sınırlarıyla çakıştığında sıfır olmayan yerleştirme değerleri 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 yerleştirmeleri sıfır olarak almalıdır.

Bu varsayılan mantığı geçersiz kılmak ve web içeriğini çakışmadan bağımsız olarak tam sistem boyutlarıyla sağlamak için setOnApplyWindowInsetsListener yöntemini kullanın ve dinleyiciden orijinal, değiştirilmemiş windowInsets nesnesini döndürün. Tam sistem boyutları sağlamak, WebView'ın mevcut konumundan bağımsız olarak web içeriğinin cihaz donanımıyla uyumlu olmasını sağlayarak tasarım tutarlılığını korumaya yardımcı olabilir. Bu sayede, WebView ekran kenarlarına dokunmak için 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ı yeniden boyutlandırması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 vermemesini sağlamalıdır. Bu durumda, odak kaybı ve klavyenin kapatılmasıyla ilgili bir döngü oluşur ve kullanıcı girişi engellenir:

  1. Kullanıcı bir giriş öğesine odaklanıyor.
  2. Klavye göründüğünde yeniden boyutlandırma etkinliği tetiklenir.
  3. Web sitesinin kodu, yeniden boyutlandırmaya yanıt olarak odağı temizler.
  4. Odak kaybolduğu için klavye gizlenir.

Bu davranışı azaltmak için web tarafındaki dinleyicileri inceleyerek görünüm alanı değişikliklerinin blur() JavaScript işlevini veya odak temizleme davranışlarını yanlışlıkla tetiklemediğinden emin olun.

Yerleştirme işleme özelliğini uygulama

WebView'ın varsayılan ayarları çoğu uygulama için otomatik olarak çalışır. Ancak uygulamanız özel düzenler kullanıyorsa (ör. durum çubuğunu veya klavyeyi hesaba katmak için kendi dolgunuzu ekliyorsanız) 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. Doğal kullanıcı arayüzünüz WindowInsets temelinde 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ç boyutları uyguladığı ve gereksiz boşluklara neden olduğu bir durumdur. Örneğin, 40 piksel durum çubuğu olan bir telefonu düşünün. Hem yerel görünüm hem de WebView, 40 piksel iç kenarı görür. Her ikisi de 40 piksel dolgu eklediğinden kullanıcı, üstte 80 piksellik bir boşluk görür.

Sıfırlama yaklaşımı

Çift dolguyu önlemek için bir doğal görünüm dolgu için yerleştirilmiş bir boyut kullandıktan sonra, değiştirilen nesneyi görünüm hiyerarşisinde WebView'a aktarmadan önce yeni bir WindowInsets nesnesinde Insets.NONE kullanarak bu boyutu sıfıra sıfırladığınızdan emin olmanız gerekir.

Bir üst görünüme dolgu uygularken genellikle WindowInsetsCompat.CONSUMED yerine Insets.NONE ayarlanarak sıfırlama yaklaşımı kullanılmalıdır. Geri dönme WindowInsetsCompat.CONSUMED bazı durumlarda işe yarayabilir. Ancak uygulamanızın işleyicisi, yerleştirmeleri değiştirir veya kendi dolgusunu eklerse sorunlar yaşanabilir. Sıfırlama yaklaşımında bu sınırlamalar yoktur.

İç kısımları sıfırlayarak hayalet dolgudan kaçının

Uygulama daha önce kullanılmamış yerleşimler ilettiğinde yerleşimleri kullanırsanız veya yerleşimler değişirse (ör. klavye gizlendiğinde) bunları kullanmak WebView'un gerekli güncelleme bildirimini almasını engeller. Bu durum, WebView'un önceki bir durumdan hayalet dolguyu korumasına (örneğin, klavye gizlendikten sonra klavye dolgusunu koruması) neden olabilir.

Aşağıdaki örnekte, uygulama ile WebView arasındaki bozuk bir etkileşim gösterilmektedir:

  1. İlk durum: Uygulama başlangıçta tüketilmemiş yerleştirmeleri (ör. displayCutout() veya systemBars()) WebView'a geçirir. Bu da web içeriğine dahili olarak dolgu uygular.
  2. Durum değişikliği ve hata: Uygulama durum değiştirirse (örneğin, klavye gizlenirse) ve uygulama, sonuçtaki iç kısımları WindowInsetsCompat.CONSUMED döndürerek işlemeyi seçerse.
  3. Bildirim engellendi: Yerleştirme alanlarının kullanılması, Android sisteminin gerekli güncelleme bildirimini görünüm hiyerarşisinde WebView'a göndermesini engeller.
  4. Hayalet dolgu: WebView güncellemeyi almadığı için önceki durumdaki dolguyu korur ve hayalet dolguya neden olur (örneğin, klavye gizlendikten sonra klavye dolgusunu korur).

Bunun yerine, nesneyi alt görünümlere aktarmadan önce işlenen türleri sıfıra ayarlamak için WindowInsetsCompat.Builder kullanın. Bu, WebView'a söz konusu belirli yerleştirmelerin zaten hesaba katıldığını bildirirken 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 işlemini nasıl gerçekleştirebilirsiniz?

Bu modern davranışları devre dışı bırakmak ve eski görünüm alanı işlemeye dönmek için aşağıdakileri yapın:

  1. Kesici ekler: WebView alt sınıfında setOnApplyWindowInsetsListener kullanın veya onApplyWindowInsets öğesini geçersiz kılın.

  2. Net yerleşimler: Tüketilen bir yerleşim grubunu (örneğin, WindowInsetsCompat.CONSUMED) baştan döndürün. Bu işlem, yerleştirilmiş bildirimin WebView'e tamamen yayılmasını önler. Böylece modern görünüm alanı yeniden boyutlandırma özelliği devre dışı bırakılır ve WebView, ilk görsel görünüm alanı boyutunu korumaya zorlanır.