😫【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)
?? 總結
就這么簡單幾步,我終于實現了一個:
- 沉浸式狀態欄 ?
- 本地網頁不被遮擋 ?
- 頁面美觀可控 ?
- 腳本注入可調節 ?
如果你正好也在做類似項目,希望這篇能給你節省幾個小時人生!
📣 如果你覺得有用
點個贊 ? 收藏一下 💾
關注我,后面會繼續分享更多原生 + 前端混合開發的踩坑記錄!