支援螢幕凹口

試試 Compose
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中處理螢幕凹口。

螢幕凹口是某些裝置上延伸至螢幕表面的區域。可提供無邊框體驗,同時為裝置正面的重要感應器保留空間。

Android 支援在搭載 Android 9 (API 級別 28) 以上版本的裝置上顯示螢幕凹口。不過,裝置製造商也可以在搭載 Android 8.1 以下版本的裝置上支援螢幕凹口。

本文說明如何實作支援有凹口的裝置,包括如何使用凹口區域,也就是螢幕表面上包含凹口的無邊框矩形。

圖片:顯示頂端中央螢幕凹口的範例
圖 11 螢幕凹口。

選擇應用程式處理凹口區域的方式

如要避免內容與凹口區域重疊,一般來說,只要確保內容不會與狀態列和導覽列重疊即可。如要將內容算繪到凹口區域,請使用 WindowInsetsCompat.getDisplayCutout() 擷取 DisplayCutout 物件,其中包含每個凹口的安全性插邊和定界框。這些 API 可讓您檢查內容是否與凹口重疊,以便視需要重新調整位置。

您也可以決定內容是否要顯示在凹口區域後方。layoutInDisplayCutoutMode 視窗版面配置屬性可控制內容在凹口區域的繪製方式。 您可以將 layoutInDisplayCutoutMode 設為下列任一值:

  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:如果系統資訊列包含螢幕凹口,內容會顯示在凹口區域。否則視窗不會與螢幕凹口重疊;舉例來說,以橫向模式顯示時,內容可能會出現上下黑邊。如果應用程式的目標是 SDK 35,系統會將此解讀為ALWAYS (適用於非浮動視窗)。
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS:內容一律可延伸至凹口區域。如果應用程式以 SDK 35 為目標版本,且在 Android 15 裝置上執行,這是非浮動視窗唯一允許的模式,可確保顯示無邊框畫面。
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES: 在直向和橫向模式下,內容都會轉譯到凹口區域。請勿用於浮動視窗。如果應用程式指定 SDK 35,系統會將此值解讀為非浮動視窗的 ALWAYS
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER: 內容絕不會在螢幕凹口區域中顯示。如果應用程式指定 SDK 35,系統會將此解讀為非浮動視窗的 ALWAYS

您可以透過程式輔助方式設定凹口模式,或是在活動中設定樣式。下列範例定義樣式,將 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 屬性套用至活動。

<style name="ActivityTheme">
  <item name="android:windowLayoutInDisplayCutoutMode">
    shortEdges <!-- default, shortEdges, or never -->
  </item>
</style>

以下各節將詳細說明不同的剪裁模式。

預設行為

如果應用程式以 SDK 35 為目標版本,且在 Android 15 裝置上執行,則 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS 是預設行為,且系統會將 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 解讀為非浮動視窗的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS

否則預設為 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT

在短邊凹口區域中顯示內容

如果應用程式以 SDK 35 為目標版本,且在 Android 15 裝置上執行,系統會將 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES解讀為 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS (非浮動視窗)。

使用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 時,無論系統資訊列是否隱藏或顯示,內容都會在直向和橫向模式下延伸至螢幕短邊的凹口區域。使用這個模式時,請務必確認重要內容不會與凹口區域重疊。

下圖是直向裝置的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 範例:

圖片:顯示直向模式下,內容在螢幕凹口區域的算繪情形
圖 2 在直向模式下,內容會顯示在凹口區域。

下圖為橫向裝置的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 範例:

圖片:顯示橫向模式下,內容轉譯到螢幕凹口區域的樣子
圖 3. 在橫向模式下,內容會算繪到凹口區域。

無論視窗是否隱藏系統資訊列,在此模式下,視窗都會在直向和橫向模式中,延伸至螢幕短邊的凹口下方。

角落的凹口會視為位於短邊:

圖片:裝置一角有凹口
圖 4. 有角落凹口的裝置。

永不在螢幕凹口區域中算繪內容

如果應用程式以 SDK 35 為目標版本,且在 Android 15 裝置上執行,系統會將 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER解讀為 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS (非浮動視窗)。

使用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 時,視窗一律不得與凹口區域重疊。

以下是直向模式的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 範例:

圖片:顯示直向模式的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
圖 5. 肖像模式的示例 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER

以下是橫向模式的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 範例:

圖片:顯示橫向模式的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
圖 6. 橫向模式下的「LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER」範例。

螢幕凹口支援最佳做法

處理螢幕凹口時,請考量下列事項:

  • 請注意使用者介面重要元素的放置位置。請勿讓凹口區域遮住任何重要文字、控制項或其他資訊。
  • 請勿將需要精細觸控辨識的互動元素放置或延伸至剪裁區域。螢幕凹口區域的觸控敏感度可能較低。
  • 請盡可能使用 WindowInsetsCompat 擷取狀態列高度,並判斷要套用至內容的適當邊框間距。請避免將狀態列高度硬式編碼,否則可能會導致內容重疊或遭到截斷。

    圖片:由於插邊設定不當,頂端內容遭到裁剪
    圖 7. 使用 WindowInsetsCompat 避免內容重疊或遭到截斷。
  • 使用 View.getLocationInWindow() 判斷應用程式使用的視窗空間大小。請勿假設應用程式可完整占用整個視窗,也不要使用 View.getLocationOnScreen()

  • 如果應用程式需要進入和退出沉浸模式,請使用 alwaysshortEdgesnever 螢幕凹口模式。預設的凹口行為可能會導致應用程式內容在系統資訊列存在時,於凹口區域中轉譯,但不會在沉浸模式下發生。這會導致內容在轉場期間上下移動,如下列範例所示。

    圖片:顯示內容在轉場期間向上和向下移動。
    圖 8. 在轉場期間,內容會上下移動,如圖所示。
  • 在沉浸模式中,請小心使用視窗與螢幕座標,因為應用程式加上黑邊時不會使用整個螢幕。由於有上下黑邊,螢幕原點的座標與視窗原點的座標不同。您可以使用 getLocationOnScreen(),視需要將螢幕座標轉換為檢視區塊的座標。下圖顯示內容加上上下黑邊時,座標的差異:

    圖片:內容加上上下黑邊時的視窗與螢幕座標。
    圖 9. 內容加上上下黑邊時的視窗與螢幕座標。
  • 處理 MotionEvent 時,請使用 MotionEvent.getX()MotionEvent.getY(),避免發生類似的座標問題。請勿使用 MotionEvent.getRawX()MotionEvent.getRawY()

測試內容的算繪方式

測試應用程式的所有畫面和體驗。盡可能在不同類型的凹口裝置上測試。如果沒有具備凹口的裝置,您可以在搭載 Android 9 以上版本的任何裝置或模擬器上,模擬常見的凹口設定,方法如下:

  1. 啟用「開發人員選項」。
  2. 在「開發人員選項」畫面中,向下捲動至「繪圖」部分,然後選取「模擬有凹口的螢幕」
  3. 選取凹口類型。

    圖片:顯示如何在模擬器中模擬螢幕凹口
    圖 10. 開發人員選項,可測試內容的轉譯方式。

其他資源