Android statuBar 遮挡问题解决方案

150 阅读1分钟

用经典的 DrawerLayout 和 NavigationView 的遮挡为例: 不说废话,解决方案如下:

1. 使用 fitsSystemWindows 属性

在你的 DrawerLayout 中设置 android:fitsSystemWindows="true"。这可以让 DrawerLayout 自动处理系统窗口(包括状态栏):

<androidx.drawerlayout.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- Main content layout -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!--  content -->
    </FrameLayout>

    <!-- Navigation view -->
    <com.google.android.material.navigation.NavigationView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true">
        <!-- navigation menu -->
    </com.google.android.material.navigation.NavigationView>

</androidx.drawerlayout.widget.DrawerLayout>

2. 设置 Window Flags

onCreate 方法中,通过代码来设置系统 UI 可见性:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // 设置全屏布局模式
    window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
                                          View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

    // 如果你希望透明状态栏
    window.statusBarColor = Color.TRANSPARENT
}

3. 使用 WindowInsetsController (API 30+)

在 Android 11 (API 30) 及以上,你可以使用 WindowInsetsController 来处理系统窗口:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val windowInsetsController = window.insetsController
    if (windowInsetsController != null) {
        windowInsetsController.hide(WindowInsets.Type.statusBars())
        windowInsetsController.systemBarsBehavior = 
            WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    }
}

4. 设置 DrawerLayout 的 ClipToPadding

你可以通过代码设置 DrawerLayoutclipToPadding 属性为 false,这将允许内容在状态栏下显示:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout)
    drawerLayout.clipToPadding = false
}

5. 使用 ViewCompat 进行窗口插入处理

使用 ViewCompat 来请求调整 DrawerLayout 的窗口插入:

ViewCompat.setOnApplyWindowInsetsListener(drawerLayout) { view, insets ->
    val insetsCompat = ViewCompat.onApplyWindowInsets(view, insets)
    insetsCompat.consumeSystemWindowInsets()
}