Android導航抽屜 Navigation Drawer 實現沉浸通知欄

在使用 Navigation Drawer Activity 模版的時候,遇到了通知欄無法完全沉浸的問題,嘗試搜索一些現有的解決方法,但是或多或少都會存在一些問題,通過反覆嘗試找到找到了一種比較靠譜的思路

環境

測試模擬器:Pixel 3A

compileSdk:32

minSdk:28

targetSdk:32

創建工程


默認效果展示:


修改步驟

  1. 設置狀態欄變為透明:修改主題配置
 <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>

修改為:

<item name="android:statusBarColor">@android:color/transparent</item>

修改後完整文件:

<resources>
    <!-- Base application theme. -->
    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
+       <item name="android:statusBarColor">@android:color/transparent</item>
        <!-- Customize your theme here. -->
    </style>

    <style name="Theme.MyApplication.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="Theme.MyApplication.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

    <style name="Theme.MyApplication.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

修改後的效果:

打開抽屜發現已經透明,但是會覆蓋一層淺色陰影

  1. 在布局中增加 fitsSystemWindows 屬性

app_bar_main.xmlandroidx.coordinatorlayout.widget.CoordinatorLayoutcom.google.android.material.appbar.AppBarLayout 中增加:android:fitsSystemWindows="true",這樣它會自動的給View增加一個值等於狀態欄高度的 PaddingTop,讓它的背景顏色佔據狀態欄

完整程式碼:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="//schemas.android.com/apk/res/android"
    xmlns:app="//schemas.android.com/apk/res-auto"
    xmlns:tools="//schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
+   android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
+       android:fitsSystemWindows="true"
        android:theme="@style/Theme.MyApplication.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/Theme.MyApplication.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_main" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_marginEnd="@dimen/fab_margin"
        android:layout_marginBottom="16dp"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

效果:


  1. 修改 activity_main.xml,給 com.google.android.material.navigation.NavigationView 增加上 app:insetForeground="@android:color/transparent",去除抽屜狀態欄淺色陰影,

效果:

  1. 兼容深色模式

切換到深色模式的效果:

修改:night/themes.xml

android:statusBarColor 設置為:@android:color/transparent

<item name="android:statusBarColor">@android:color/transparent</item>

打開抽屜發現,這個時候狀態欄已經透明了,但是狀態欄背景還是會有一個黑色的背景色


修改 app_bar_main.xml,在 <com.google.android.material.appbar.AppBarLayout 中增加背景色,就可以了

android:background="?attr/colorPrimary"

最終效果:

fitsSystemWindows 屬性

android:fitsSystemWindows="true"官方文檔描述

Boolean internal attribute to adjust view layout based on system windows such as the status bar.
If true, adjusts the padding of this view to leave space for the system windows.
Will only take effect if this view is in a non-embedded activity.

對某個 View 設置 fitsSystemWindows 為 true,本質就是給這個 View 設置了 padding,所以在 app_bar_main.xml 的 AppBarLayout 設置 fitsSystemWindows,這樣可以使得 AppBarLayout 的背景可以通過 padding 延展到狀態欄,通過對 AppBarLayout 設置背景,就可以到達沉浸狀態欄的效果

其他常用配置

設置狀態欄為淺色模式(文字為黑字)

程式碼:

val controller = ViewCompat.getWindowInsetsController(binding.root)
controller?.isAppearanceLightStatusBars = true

或者使用主題 xml 來定義:

<item name="android:windowLightStatusBar">true</item>

參考資料

深色主題背景
What exactly does fitsSystemWindows do?
No Action Bar & Transparent Status Bar
Android沉浸式狀態欄(透明狀態欄)最佳實現
透明狀態欄、全螢幕應用、沉浸模式
NavigationView陰影
訂製你的Toolbar
Android 的style和theme

Tags: