😫【2025年4月18日】搞了一整天,终于完美搞定 Android 沉浸式状态栏(WebView + 本地HTML)
最近在做一个个人项目,用 Android 加载本地 HTML 做个小工具。按理说用 WebView 加载页面很简单嘛——结果沉浸式状态栏这个坑,属实给我干破防了……
🕳️ 坑1:状态栏怎么都不透明
🕳️ 坑2:透明了但网页内容被遮住
🕳️ 坑3:参考了N篇博客,全是复制粘贴,没一个能跑通!
搞了一天一夜,终于悟了,自己亲手撸出来一个真正完美兼容 WebView 的沉浸式状态栏方案。写这篇就是为了拯救和我一样被状态栏折磨的开发者们 🙃
🌈 最终效果(说人话)
- 状态栏透明 ✅
- 页面内容不被遮挡 ✅
- 支持动态适配状态栏高度 ✅
- 全部代码简洁明了,不用配置一堆神秘 style ✅
🧠 我的解决方案
- 把状态栏设成透明(但不隐藏);
- 把 WebView 填充到全屏;
- 加载网页后,动态设置 HTML 顶部的
padding-top
,让内容往下移动,刚好避开状态栏!
🧪 完整代码(就是这货,拯救了我)
📄 MainActivity.kt
package com.example.testimport android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity@Suppress("DEPRECATION")
class MainActivity : AppCompatActivity() {private lateinit var webView: WebViewprivate var doubleBackToExitPressedOnce = false@SuppressLint("SetJavaScriptEnabled")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREENor View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)window.statusBarColor = Color.TRANSPARENTwebView = WebView(this)setContentView(webView)val webSettings = webView.settingswebSettings.javaScriptEnabled = truewebSettings.loadsImagesAutomatically = truewebSettings.domStorageEnabled = truewebSettings.cacheMode = WebSettings.LOAD_DEFAULTwebSettings.allowFileAccess = truewebSettings.allowFileAccessFromFileURLs = truewebSettings.allowUniversalAccessFromFileURLs = truewebSettings.useWideViewPort = truewebSettings.loadWithOverviewMode = true// 防止跳转到外部浏览器webView.webViewClient = WebViewClient()webView.webViewClient = object : WebViewClient() {override fun onPageFinished(view: WebView?, url: String?) {val height = getStatusBarHeight()webView.evaluateJavascript("document.getElementsByClassName('header')[0].style.paddingTop ='${height}px';",null)}}// 加载本地 HTMLwebView.loadUrl("file:///android_asset/index.html")}override fun onBackPressed() {if (webView.canGoBack()) {webView.goBack()} else {if (doubleBackToExitPressedOnce) {super.onBackPressed()return}this.doubleBackToExitPressedOnce = trueToast.makeText(this, "再按一次退出程序", Toast.LENGTH_SHORT).show()Handler(Looper.getMainLooper()).postDelayed({doubleBackToExitPressedOnce = false}, 2000)}}@SuppressLint("DiscouragedApi")fun getStatusBarHeight(): Double {val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")val px = if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else 0val density = resources.displayMetrics.densityval dp = (px / density).toInt() // 转为逻辑像素return dp*1.2 // 多乘点,保险一点}}
🎨 res/values/themes.xml
<resources xmlns:tools="http://schemas.android.com/tools"><style name="Theme.Test" parent="Theme.AppCompat.NoActionBar"><item name="android:windowNoTitle">true</item><item name="android:windowFullscreen">true</item><item name="windowActionBar">false</item></style>
</resources>
🧩 遇到的几个“小坑提示”
- 状态栏高度是 px,要转成 dp 后加到网页上才舒服,不然有时显示偏差一丢丢。
document.getElementsByClassName('header')[0].style.paddingTop ='${height}px';
请根据自己的网页内容来修改(比如给body设置,而不是我这边的.header的class)
✌️ 总结
就这么简单几步,我终于实现了一个:
- 沉浸式状态栏 ✅
- 本地网页不被遮挡 ✅
- 页面美观可控 ✅
- 脚本注入可调节 ✅
如果你正好也在做类似项目,希望这篇能给你节省几个小时人生!
📣 如果你觉得有用
点个赞 ⭐ 收藏一下 💾
关注我,后面会继续分享更多原生 + 前端混合开发的踩坑记录!