1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Android WebViewでアプリ内ブラウザを作るときはWindowInsetsの扱いに気をつけよう

1
Last updated at Posted at 2026-09-06

以前、以下の記事を書いたのですが、また、アプリ上でのWebViewの扱いによってWebコンテンツ側に影響が出る要素を知ったので書きます。

CSSでは safe-area-inset-* という環境変数でセーフエリアのサイズを取得することができます。たとえば、画面上部のセーフエリアを知りたい場合は env(safe-area-inset-top, 0px) とすることで取得できます。
Androidでは、ディスプレイカットアウトやステータスバー、ナビゲーションバーなどを考慮して、コンテンツを安全に配置するためのInsetsが提供されており、WebViewはこの値を元にセーフエリアの値を決定しています。

Edge-to-Edgeで表示されるPWAでは、セーフエリアも含んだ領域が与えられます。セーフエリアに重要なコンテンツが重ならないようにマージンを設定するために使われます。
しかし、一般のWebViewを使ったアプリ内ブラウザでは、ツールバーやボトムナビなどを持っている場合も多いですし、仮に全画面の場合でもネイティブ側でセーフエリアの処理を行い、WebViewを配置している場合が多いかと思います。その場合、適切にWindowInsetsの伝搬を止めておかないと、Webコンテンツ側で不要なマージンが出てしまいます。

WindowInsetsをアプリで扱う場合、ViewCompat.setOnApplyWindowInsetsListener()を使って以下のような実装をすると思います。

ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
    val types = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
    val insets = windowInsets.getInsets(types)
    binding.appBarLayout.updatePadding(
        top = insets.top,
        left = insets.left,
        right = insets.right
    )
    binding.webView.updatePadding(
        bottom = insets.bottom,
        left = insets.left,
        right = insets.right
    )
    windowInsets
}

戻り値は子Viewへ伝えるWindowInsetsですが、通常は子ViewにもInsetsを伝える必要があるので、特に意識せずこのような実装をしてしまっているのではないでしょうか?
WebViewを設置している画面の場合、Webコンテンツへの伝搬も考慮する必要があります。
WebViewが後段でWindowInsetsを参照して、safe-area-inset-* として使用しているからです。

子Viewに伝えたくない場合は、WindowInsetsCompat.CONSUMEDを戻すという方法もあります。

ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
    // 略
    WindowInsetsCompat.CONSUMED
}

ただ、これをやってしまうと、本来WindowInsetsを使って行われる他の処理が正しく動かなくなってしまいます。WindowInsetsが伝搬しているのはディスプレイカットアウトや、システムUIのエリアだけではありません。また、イベントそのものが通知されなくなるため0を伝えることもできなくなります。

より正しくは、処理済みのInsetsについて Insets.NONE を設定し、後段にその値が0であると伝えるのがよいです。

ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
    val types = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
    val insets = windowInsets.getInsets(types)
    // 略
    WindowInsetsCompat.Builder(windowInsets)
        .setInsets(types, Insets.NONE)
        .build()
}

WebViewはPlayストア経由でアップデートされるため、OSの差分を追っているだけではこのような新しい機能や振る舞いの変化に気づけませんし、Webコンテンツ側の知識もないとどのような影響があるかわかりにくい部分です。
ネイティブ側の実装内容がWebコンテンツに影響することがあると認識して、定期的にチェックを行うようにしましょう。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?