在應用程式中以無邊框方式顯示內容

試試 Compose 的方式
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中處理無邊框。

在搭載 Android 15 以上版本的裝置上指定 SDK 35 以上版本後,應用程式就會以無邊框畫面顯示。視窗會在系統資訊列後方繪製,橫跨整個螢幕的寬度和高度。系統資訊列包括狀態列、說明文字列和導覽列。

許多應用程式都有頂端應用程式列。頂端應用程式列應延伸至螢幕頂端邊緣,並顯示在狀態列後方。您可以選擇在內容捲動時,將頂端應用程式列縮小至狀態列的高度。

許多應用程式也有底部應用程式列或底部導覽列。這些列也應延伸至畫面底部邊緣,並顯示在導覽列後方。否則,應用程式應在導覽列後方顯示捲動內容。

圖 1. 無邊框版面配置中的系統資訊列。

在應用程式中實作從邊到邊的版面配置時,請注意下列事項:

  1. 啟用無邊框螢幕
  2. 處理任何視覺重疊問題。
  3. 建議您在系統資訊列後方顯示遮罩。
狀態列後方的圖像範例
圖 2. 狀態列後方圖像示例。

啟用無邊框顯示

如果應用程式指定目標為 SDK 35 以上版本,系統會自動為 Android 15 以上版本的裝置啟用無邊框畫面。

如要在舊版 Android 上啟用邊到邊功能,請按照下列步驟操作:

  1. 在應用程式或模組的 build.gradle 檔案中,新增 androidx.activity 程式庫的依附元件:

    Kotlin

    dependencies {
        val activity_version = activity_version
        // Java language implementation
        implementation("androidx.activity:activity:$activity_version")
        // Kotlin
        implementation("androidx.activity:activity-ktx:$activity_version")
    }
    

    Groovy

    dependencies {
        def activity_version = activity_version
        // Java language implementation
        implementation 'androidx.activity:activity:$activity_version'
        // Kotlin
        implementation 'androidx.activity:activity-ktx:$activity_version'
    }
    
  2. enableEdgeToEdge 擴充功能函式匯入應用程式:

ActivityonCreate 中呼叫 enableEdgeToEdge,即可手動啟用無邊框顯示。應在 setContentView 之前呼叫。

Kotlin

     override fun onCreate(savedInstanceState: Bundle?) {
       enableEdgeToEdge()
       super.onCreate(savedInstanceState)
       ...
     }
   

Java

     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
       EdgeToEdge.enable(this);
       super.onCreate(savedInstanceState);
       ...
     }
   

根據預設,enableEdgeToEdge() 會將系統列設為透明,但在 3 鍵導覽模式下,狀態列會變成半透明的遮罩。系統圖示和遮罩的顏色會根據系統的淺色或深色主題進行調整。

enableEdgeToEdge() 函式會自動宣告應用程式應以從邊到邊的方式進行版面配置,並調整系統列的顏色。

如要在應用程式中啟用無邊框顯示,但不使用 enableEdgeToEdge() 函式,請參閱「手動設定無邊框顯示」。

使用內嵌處理重疊

部分應用程式檢視畫面可能會繪製在系統列後方,如圖 3 所示。

您可以回應內嵌,藉此解決重疊問題。內嵌會指定畫面中與系統 UI (例如導覽列或狀態列) 重疊的部分。交疊可表示顯示在內容上方,但也可以讓應用程式瞭解系統手勢。

適用於邊到邊顯示應用程式的內嵌類型如下:

  • 系統資訊列內嵌:最適合可點選且不得遭系統資訊列遮蔽的檢視畫面。

  • 顯示螢幕邊框:適用於因裝置形狀而可能出現螢幕邊框的區域。

  • 系統手勢內嵌:系統使用的手勢導覽區域,優先於應用程式。

系統列內嵌

系統列邊框是最常用的邊框類型。這些區域代表系統 UI 在應用程式上方 Z 軸顯示的區域。這些區域最適合用於移動或填充應用程式中的可點選檢視畫面,且不得讓系統列遮蔽檢視畫面。

舉例來說,圖 3 中的懸浮動作按鈕 (FAB) 部分遭到導覽列遮蔽:

實作了從邊到邊的範例,但導覽列遮蓋了懸浮動作按鈕
圖 3. 導覽列在邊到邊版面配置中與 FAB 重疊。

如要在手勢模式或按鈕模式中避免這種視覺重疊情形,您可以使用 getInsets(int) 搭配 WindowInsetsCompat.Type.systemBars() 增加檢視畫面的邊界。

以下程式碼範例說明如何實作系統列內嵌:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets ->
  val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
  // Apply the insets as a margin to the view. This solution sets
  // only the bottom, left, and right dimensions, but you can apply whichever
  // insets are appropriate to your layout. You can also update the view padding
  // if that's more appropriate.
  v.updateLayoutParams<MarginLayoutParams> {
      leftMargin = insets.left,
      bottomMargin = insets.bottom,
      rightMargin = insets.right,
  }

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> {
  Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
  // Apply the insets as a margin to the view. This solution sets only the
  // bottom, left, and right dimensions, but you can apply whichever insets are
  // appropriate to your layout. You can also update the view padding if that's
  // more appropriate.
  MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
  mlp.leftMargin = insets.left;
  mlp.bottomMargin = insets.bottom;
  mlp.rightMargin = insets.right;
  v.setLayoutParams(mlp);

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

如果您將這個解決方案套用至圖 3 所示的範例,則按鈕模式不會出現視覺重疊,如圖 4 所示:

半透明導覽列不會遮蓋 FAB
圖 4. 解決按鈕模式中的視覺重疊問題。

這項原則也適用於手勢導覽模式,如圖 5 所示:

無邊框設計,並採用手勢操作
圖 5. 解決手勢操作模式中的視覺重疊問題。

顯示螢幕凹口內嵌

部分裝置有螢幕缺口。通常,裁切區會位於螢幕頂端,並包含在狀態列中。裝置螢幕處於橫向模式時,螢幕邊緣可能會出現缺口。根據應用程式在螢幕上顯示的內容,您應實作邊框間距,以免顯示螢幕缺口,因為根據預設,應用程式會在顯示螢幕缺口中繪製內容。

舉例來說,許多應用程式畫面都會顯示項目清單。請勿讓螢幕缺口或系統列遮蓋清單項目。

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets ->
  val bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
      or WindowInsetsCompat.Type.displayCutout()
  )
  v.updatePadding(
    left = bars.left,
    top = bars.top,
    right = bars.right,
    bottom = bars.bottom,
  )
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> {
  Insets bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
    | WindowInsetsCompat.Type.displayCutout()
  );
  v.setPadding(bars.left, bars.top, bars.right, bars.bottom);
  return WindowInsetsCompat.CONSUMED;
});

請使用系統列和顯示螢幕缺孔類型的邏輯 or,判斷 WindowInsetsCompat 的值。

clipToPadding 設為 RecyclerView,讓邊框與清單項目一起捲動。這樣一來,使用者捲動畫面時,系統資訊列後方就會顯示項目,如以下範例所示。

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

系統手勢內嵌

系統手勢內嵌表示視窗的哪些區域系統手勢優先於應用程式。這些區域在圖 6 中以橘色標示:

系統手勢內嵌範例
圖 6. 系統手勢內嵌。

如同系統列內嵌區塊,您可以使用 getInsets(int) 搭配 WindowInsetsCompat.Type.systemGestures(),避免系統手勢內嵌區塊重疊。

使用這些內嵌,將可滑動的檢視區塊移離邊緣,或在邊緣加上緩衝區。常見的用途包括底部資訊卡、遊戲中的滑動操作,以及使用 ViewPager2 實作的輪轉介面。

在 Android 10 以上版本中,系統手勢插邊包含主畫面手勢的底部插邊,以及返回手勢的左右插邊:

系統手勢內縮測量值示例
圖 7. 系統手勢內縮測量。

以下程式碼範例說明如何實作系統手勢內嵌:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.updatePadding(insets.left, insets.top, insets.right, insets.bottom)

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures());
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Material Design 元件

許多以 View 為基礎的 Android Material 元件 (com.google.android.material){:.external} 會自動處理插邊,包括 BottomAppBarBottomNavigationViewNavigationRailViewNavigationView

不過,AppBarLayout 不會自動處理內嵌區塊。新增 android:fitsSystemWindows="true" 來處理頂端插邊。

請參閱Compose 中的 Material Design 元件,瞭解如何處理內嵌區。

沉浸模式

某些內容最適合以全螢幕模式觀看,可為使用者提供更身歷其境的體驗。您可以使用 WindowInsetsControllerWindowInsetsControllerCompat 程式庫,在沈浸模式下隱藏系統資訊列:

Kotlin

val windowInsetsController =
      WindowCompat.getInsetsController(window, window.decorView)

// Hide the system bars.
windowInsetsController.hide(Type.systemBars())

// Show the system bars.
windowInsetsController.show(Type.systemBars())

Java

Window window = getWindow();
WindowInsetsControllerCompat windowInsetsController =
      WindowCompat.getInsetsController(window, window.getDecorView());
if (windowInsetsController == null) {
    return;
  }
// Hide the system bars.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

// Show the system bars.
windowInsetsController.show(WindowInsetsCompat.Type.systemBars());

如要進一步瞭解如何實作這項功能,請參閱「在沈浸模式下隱藏系統資訊列」。

系統資訊列保護功能

應用程式指定目標為 SDK 35 以上版本後,系統會強制執行無邊框設計。系統狀態列和手勢導覽列為透明,但三按鈕導覽列則為半透明。

如要移除預設的半透明三按鈕操作模式背景保護措施,請將 Window.setNavigationBarContrastEnforced 設為 false

其他資源

如要進一步瞭解 WindowInsets、手勢導覽和插邊的運作方式,請參閱下列參考資料: