PAYATHON 2026

Android WebView 如何为导航栏添加底部留白?

数据小许

结论

启用 edge-to-edge 后,可以通过 WindowInsetsCompat.Type.navigationBars() 获取导航栏占用的底部空间,再将它加到 WebView 的底部 padding。这样能为 WebView 的可视区域留出空间。如果还需要让 HTML 文档滚动到底部时完整显示内容,可能也要给页面内容增加相应的底部留白。

透明导航栏需要在 Activity 的 Window 上设置,Insets listener 用来处理 WebView 的留白。

设置 edge-to-edge 和透明导航栏

在承载该 Fragment 的 Activity 中设置 Window。下面的示例使用 AndroidX Core 的 WindowCompat 和 WindowInsetsControllerCompat:

WindowCompat.setDecorFitsSystemWindows(window, false)
window.navigationBarColor = android.graphics.Color.TRANSPARENT

WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightNavigationBars = true

如果导航栏图标需要浅色,将 isAppearanceLightNavigationBars 设为 false;设为 true 时使用深色图标。透明导航栏区域的对比度效果可能因应用主题和系统行为而异,建议在目标设备上检查。

将导航栏插入区应用到 WebView

在 Fragment 中使用同一个 WebView 引用,并在设置 listener 前保存原始 padding。每次 Insets 更新时都根据原始值计算,避免重复叠加:

val webView = binding.webView
val initialPaddingBottom = webView.paddingBottom

ViewCompat.setOnApplyWindowInsetsListener(webView) { view, insets ->
    val navigationBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
    view.updatePadding(
        bottom = initialPaddingBottom + navigationBars.bottom
    )
    insets
}

ViewCompat.requestApplyInsets(webView)

问题中的 listener 使用 binding.parishNoticeDetailsWebView,而加载内容的代码使用 binding.webView。请确认这两个引用指向同一个实际视图;否则 Insets 不会应用到正在显示内容的 WebView。

如果滚动到底部仍有内容被遮挡

原生 View 的 padding 不一定能为 HTML 文档提供足够的滚动空间。这种情况下,可以把底部留白加到 HTML 的可滚动内容中。下面的示例将导航栏 inset 从像素换算为 CSS 像素,再设置到 body:

ViewCompat.setOnApplyWindowInsetsListener(webView) { _, insets ->
    val bottomPx = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
    val bottomCssPx = bottomPx / webView.resources.displayMetrics.density

    webView.evaluateJavascript(
        "document.body.style.paddingBottom = '${bottomCssPx}px';",
        null
    )
    insets
}

这段代码要求页面已加载,并且存在 document.body。如果 Insets 可能在页面加载前到达,可以先保存底部 inset 值,等页面加载完成后再执行 JavaScript;否则脚本调用时可能没有可更新的页面内容。是否只在原生 View 上加 padding,取决于页面的 HTML/CSS 布局和所需的滚动空间。

注意事项

  • 将 Insets listener 设置在实际显示的 WebView 或合适的容器上,并确认该视图能收到窗口 Insets。
  • 保存原始 padding,再加上当前 inset。不要在每次回调中把新 inset 累加到已经更新的 padding 上。
  • 如果系统没有向该视图分发 Insets,请检查 Activity 是否启用了 edge-to-edge,以及父视图的 Insets 分发处理。
  • 示例通过 navigationBars() 获取导航栏插入区。如果还要处理状态栏、刘海或其他显示区域,应根据页面布局考虑相应的 Insets 类型。

备注:内容仅供参考。