Android 平台負責繪製系統 UI,例如 狀態列和導覽列無論 使用者正在使用的應用程式。
WindowInsets
提供系統相關資訊
UI 可確保應用程式繪製在正確的區域,且 UI 不會遭到遮蓋
由系統 UI 套用
在 Android 14 (API 級別 34) 以下版本中,應用程式的 UI 不會在以下之下繪製 系統資訊列和螢幕凹口。
在 Android 15 (API 級別 35) 以上版本中,如果應用程式指定 SDK 35 以上版本,應用程式會在系統列下方繪製並顯示缺口。這可提供更流暢的使用者體驗,並讓應用程式充分運用可用的視窗空間。
在系統 UI 後方顯示內容稱為「無邊框」。您將在這頁面中瞭解不同類型的內嵌、如何進行邊到邊顯示,以及如何使用內嵌 API 為 UI 製作動畫,並確保應用程式內容不會遭系統 UI 元素遮蔽。
內嵌基本概念
當應用程式採用從邊到邊的螢幕時,您必須確保系統 UI 不會遮蓋重要內容和互動。舉例來說,如果按鈕位於導覽列後方,使用者可能無法點選該按鈕。
系統 UI 大小及其位置相關資訊 透過 插邊。
系統 UI 各部分都有對應的插邊類型, 大小和位置例如,狀態列插邊會提供 和狀態列的位置,導覽列插邊則提供 導覽列的大小和位置每種插邊都包含 像素尺寸:頂端、左側、右側和底部。這些尺寸會指定系統 UI 從應用程式視窗對應側延伸的距離。為了避免 與該類型的系統 UI 重疊,因此應用程式 UI 必須透過該類型的系統插邊 金額。
您可以透過 WindowInsets
使用下列內建的 Android 內嵌類型:
說明狀態列的內嵌區域。這些是頂端系統 UI 列,內含通知圖示和其他指標。 |
|
顯示時間的狀態列插邊。如果狀態列目前處於隱藏狀態 (因為要進入沉浸模式),主要狀態列插邊將呈現空白,但這些插邊不會空白。 |
|
說明導覽列的插邊。這些是裝置左側、右側或底部的系統 UI 列,描述工作列或導覽圖示。這些目錄在執行階段可能會根據使用者偏好的導覽方法和工作列互動而變更。 |
|
導覽列插邊用於指定顯示時間。如果導覽列目前處於隱藏狀態 (因為進入全螢幕模式),則主導覽列內嵌項目會是空白,但這些內嵌項目不會是空白。 |
|
插圖:說明任意形式視窗中的系統 UI 視窗裝飾,例如頂部標題列。 |
|
字幕列顯示時間的插邊。如果目前隱藏了字幕列,主字幕列內嵌會是空白,但這些內嵌會是空白。 |
|
系統列插邊的聯合,包括狀態列、導覽列和說明文字列。 |
|
顯示時的系統資訊列插邊。如果系統資訊列目前處於隱藏狀態 (因為進入了沉浸式全螢幕模式),主系統列插邊將呈現空白,但這些插邊不會空白。 |
|
這些插邊用於說明軟體鍵盤所佔用的空間大小。 |
|
插圖說明軟體鍵盤在前面目前鍵盤動畫的空間量。 |
|
此插邊用於說明軟體鍵盤在目前的鍵盤動畫「之後」佔用的空間。 |
|
一種邊框,可說明導覽 UI 的詳細資訊,提供「輕觸」操作的空間量,由系統而非應用程式處理。對於含有手勢導覽功能的透明導覽列,部分應用程式元素可透過系統導覽 UI 輕觸。 |
|
可輕觸元素插邊顯示的時間。如果可點選元素目前處於隱藏狀態 (因為進入全螢幕模式),則主要可點選元素內嵌會為空白,但這些內嵌會非空白。 |
|
邊框代表系統會攔截手勢用於導覽的邊框數量。應用程式可以透過 |
|
系統手勢的子集,系統一律會處理這些手勢,且無法透過 |
|
內嵌表示避免與螢幕凹口 (缺口或針孔) 重疊所需的間距量。 |
|
代表瀑布螢幕曲線區域的插邊。瀑布式螢幕的螢幕邊緣有弧形區域,螢幕會從這裡開始沿著裝置兩側延伸。 |
這些類型可歸納為三種「安全」內嵌類型,可確保內容不會遭到遮蔽:
這些「安全」插邊類型會根據 基礎平台插邊:
- 使用
WindowInsets.safeDrawing
保護不應繪製的內容 顯示在任何系統 UI 底下這是插邊最常見的用法: 繪製遭系統 UI 遮蔽的內容 (可能是部分或 )。 - 使用
WindowInsets.safeGestures
透過手勢保護內容。這個 避免系統手勢與應用程式手勢 (例如底部手勢) 發生衝突 工作表、輪轉介面或遊戲)。 - 將
WindowInsets.safeContent
做為合併使用WindowInsets.safeDrawing
和WindowInsets.safeGestures
可以確保 內容沒有重疊的視覺效果,也沒有重疊的手勢。
插邊設定
如要讓應用程式完全控制繪製內容的位置,請按照下列設定步驟操作。如果沒有執行上述步驟,您的應用程式可能會在畫面背後繪製黑色或純色 系統 UI,或是不要與螢幕鍵盤同步動畫。
- 指定 SDK 35 以上版本,在 Android 15 以上版本中強制採用無邊框設計。您的應用程式 會在系統 UI 後方顯示。您可以透過處理內嵌調整應用程式的使用者介面。
- 您也可以選擇在
Activity.onCreate()
中呼叫enableEdgeToEdge()
,讓應用程式在舊版 Android 上呈現無邊框畫面。 在活動的
AndroidManifest.xml
項目中設定android:windowSoftInputMode="adjustResize"
。這項設定可讓應用程式以內嵌方式接收軟體 IME 的大小,以便在 IME 在應用程式中顯示和消失時,適當地填充及安排內容。<!-- in your AndroidManifest.xml file: --> <activity android:name=".ui.MainActivity" android:label="@string/app_name" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.MyApplication" android:exported="true">
Compose API
活動一旦開始控管所有插邊,您就可以使用 Compose API 確保內容不會遭到遮蔽,且可互動元素不會與系統 UI 重疊。這些 API 也會將您的應用程式版面配置與 插邊變更。
舉例來說,這是將插邊套用至內容的最基本方法 您整個應用程式的作業流程
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { Box(Modifier.safeDrawingPadding()) { // the rest of the app } } }
這個程式碼片段會將 safeDrawing
視窗內嵌區域套用為應用程式整個內容的邊框間距。雖然這可確保可互動的元素不會與系統 UI 重疊,但也表示沒有任何應用程式會在系統 UI 後方繪製,以達到從邊到邊的效果。為了充分利用
視窗,您需要在每個畫面上,微調插邊套用的位置
或是根據元件建構不同元件
這些插邊類型全都會自動使用 IME 動畫製作動畫 已向後移植至 API 21擴充功能中,所有使用這些內嵌項目的版面配置也會在內嵌值變更時自動顯示動畫。
使用這些插邊類型來調整可組合函式的主要方式有兩種 版面配置:邊框間距修飾符和插邊大小修飾符。
邊框間距修飾符
Modifier.windowInsetsPadding(windowInsets: WindowInsets)
會套用
將特定視窗插邊設為邊框間距,運作原理與 Modifier.padding
相同。
例如,Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
會將安全繪圖插邊套用為 4 邊的邊距。
另外,也提供幾種內建實用方法,可用於最常見的內嵌類型。Modifier.safeDrawingPadding()
是其中一種方法,相當於
Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
。兩者之間有些類似
其他插邊型別的修飾符。
內嵌大小修飾符
下列修飾符會將元件大小設為內嵌大小,藉此套用視窗內嵌的數量:
將 windowInsets 的起始端做為寬度 (例如 |
|
將 windowInsets 的端側套用為寬度 (例如 |
|
將 windowInsets 的頂部套用至高度 (例如 |
|
|
將 windowInsets 的底部套用為高度 (例如 |
如要調整佔用容器的 Spacer
大小,這些修飾符特別實用
插邊空間:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
嵌入式耗電量
內嵌邊距輔助鍵 (windowInsetsPadding
和 safeDrawingPadding
等輔助程式) 會自動使用用於邊距的內嵌邊距部分。深入研究組合樹狀結構時,巢狀插邊
邊框間距修飾符和插邊大小修飾符知道
插邊已被外部插邊邊框間距修飾符使用,且
重複使用插邊的相同部分反而會導致
額外空間
如果插入邊框已被使用,插入邊框大小修飾符也會避免重複使用相同的插入邊框。不過,由於它們會直接變更自身大小,因此不會自行使用內嵌區塊。
因此,巢狀邊框間距修飾符會自動變更 套用至每個可組合項的邊框間距。
以先前的 LazyColumn
範例為例,LazyColumn
會透過 imePadding
輔助鍵調整大小。LazyColumn
中的最後一個項目是
調整成系統資訊列底部的高度:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
輸入法編輯器關閉時,imePadding()
修飾符不會套用邊框間距,因為
輸入法編輯器沒有高度由於 imePadding()
修飾符不會套用任何邊框間距,
未耗用任何插邊,而 Spacer
的高度會是
位於系統資訊列底部的底部
輸入法編輯器開啟時,IME 插邊會配合輸入法編輯器的大小進行動畫,
imePadding()
修飾符開始套用底部邊框間距,以調整
LazyColumn
以開啟輸入法編輯器。當 imePadding()
修飾符開始套用底部邊框時,也會開始使用該內嵌量。因此,
Spacer
的高度開始減少,做為系統間距的一部分
imePadding()
修飾符已套用長條。產生
imePadding()
修飾符套用的底部邊框間距較大
大於系統資訊列,Spacer
的高度為零。
輸入法編輯器關閉後,變更會反向生效:Spacer
開始
當 imePadding()
套用的值低於
系統資訊列底部,直到最後 Spacer
與
輸入法列的底部資訊列進入動畫後,
要完成上述行為,
windowInsetsPadding
修飾符,且可同時受到其他影響
管理基礎架構
Modifier.consumeWindowInsets(insets: WindowInsets)
也會耗用插邊
與 Modifier.windowInsetsPadding
相同,但不適用於
耗用的插邊做為邊框間距這適合與插邊搭配使用
大小修飾符,向同層級表示有一定數量的插邊
:
Column(Modifier.verticalScroll(rememberScrollState())) { Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars)) Column( Modifier.consumeWindowInsets( WindowInsets.systemBars.only(WindowInsetsSides.Vertical) ) ) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) } Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars)) }
Modifier.consumeWindowInsets(paddingValues: PaddingValues)
的運作方式與使用 WindowInsets
引數的版本非常相似,但會使用任意的 PaddingValues
進行取用。這有助於傳送
如果邊框間距或間距是由
插邊邊框間距修飾符,例如一般 Modifier.padding
或固定高度
空格字元:
Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) }
如果需要未經消耗的原始視窗插邊,請直接使用 WindowInsets
值,或使用 WindowInsets.asPaddingValues()
傳回未受消耗影響的插邊 PaddingValues
。不過,由於下列警告,請盡可能使用視窗插邊邊框間距修飾符和視窗插邊大小修飾符。
插邊和 Jetpack Compose 階段
Compose 會使用基礎 AndroidX 核心 API 來更新插邊並加上動畫效果。 這項服務會使用基礎平台 API 管理插邊由於平台行為,內嵌內容與 Jetpack Compose 的階段有特殊關係。
內嵌值會在組合階段之後更新,但在版面配置階段之前更新。這表示讀取組合中插邊的值 通常會使用影格延遲的插邊值。本頁所述的內建輔助鍵,可延遲使用內嵌值,直到版面配置階段為止,藉此確保內嵌值會在更新時用於相同的框架。
使用 WindowInsets
的鍵盤 IME 動畫
您可以將 Modifier.imeNestedScroll()
套用至捲動容器,以開啟及
捲動至容器底部時自動關閉輸入法編輯器。
class WindowInsetsExampleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) setContent { MaterialTheme { MyScreen() } } } } @OptIn(ExperimentalLayoutApi::class) @Composable fun MyScreen() { Box { LazyColumn( modifier = Modifier .fillMaxSize() // fill the entire window .imePadding() // padding for the bottom for the IME .imeNestedScroll(), // scroll IME at the bottom content = { } ) FloatingActionButton( modifier = Modifier .align(Alignment.BottomEnd) .padding(16.dp) // normal 16dp of padding for FABs .navigationBarsPadding() // padding for navigation bar .imePadding(), // padding for when IME appears onClick = { } ) { Icon(imageVector = Icons.Filled.Add, contentDescription = "Add") } } }
Material 3 元件的插邊支援
為方便使用,系統內建許多 Material 3 可組合函式
(androidx.compose.material3
)。
根據可組合函式在應用程式中的放置方式,自行處理插邊
指定的 Pod 資源
插邊處理可組合項
下方列有Material Design 清單 元件 會自動處理插邊。
應用程式列
TopAppBar
/SmallTopAppBar
/CenterAlignedTopAppBar
/MediumTopAppBar
/LargeTopAppBar
:將系統列的頂端和水平兩側用作邊框,因為它會用於視窗頂端。BottomAppBar
:將系統資訊列的底部和水平兩側做為邊框間距。
內容容器
ModalDrawerSheet
/DismissibleDrawerSheet
/PermanentDrawerSheet
(模式導覽匣內的內容):將垂直和開始內嵌套用至內容。ModalBottomSheet
: 套用底部插邊。NavigationBar
:套用底部和水平內嵌。NavigationRail
:套用垂直和開始內嵌。
Scaffold
根據預設
Scaffold
敬上
提供插邊做為參數 paddingValues
,供您使用和使用。
Scaffold
不會將插邊套用至內容;而這份責任歸您所有
舉例來說,如要利用 Scaffold
內的 LazyColumn
使用這些插邊:
Scaffold { innerPadding -> // innerPadding contains inset information for you to use and apply LazyColumn( // consume insets as scaffold doesn't do it by default modifier = Modifier.consumeWindowInsets(innerPadding), contentPadding = innerPadding ) { items(count = 100) { Box( Modifier .fillMaxWidth() .height(50.dp) .background(colors[it % colors.size]) ) } } }
覆寫預設插邊
您可以變更傳遞至可組合項的 windowInsets
參數,以設定可組合項的行為。這個參數可以是不同類型的
要改為套用的視窗插邊,或傳送空白執行個體時停用:
WindowInsets(0, 0, 0, 0)
。
舉例來說,如要停用
LargeTopAppBar
、
將 windowInsets
參數設為空白執行個體:
LargeTopAppBar( windowInsets = WindowInsets(0, 0, 0, 0), title = { Text("Hi") } )
與 View 系統內嵌項目的互通性
如果畫面在同一個階層中同時含有 View 和 Compose 程式碼,您可能需要覆寫預設內嵌項目。在這種情況下,您必須 哪些應使用插邊,哪些應忽略插邊。
舉例來說,如果最外層的版面配置是 Android View 版面配置,則您應
請使用 View 系統中的插邊,並針對 Compose 忽略這些插邊。
或者,如果最外的版面配置是可組合函式,則應耗用
Compose 中的插邊,然後據此為 AndroidView
可組合函式加上邊框間距。
根據預設,每個 ComposeView
都會在 WindowInsetsCompat
消費層級使用所有內嵌項目。如要變更這項預設行為,請設定
ComposeView.consumeWindowInsets
敬上
至 false
。
資源
- Android 版「即時資訊」:功能完整的 Android 應用程式,完全使用 Kotlin 和 Jetpack Compose 建構。
- 處理 Android 15 強制採用的無邊框措施 - 這個程式碼研究室會逐步說明 Android 15 的無邊框措施
- 改善 Android 應用程式體驗的 3 個方面:Edge to Edge、預測返回和資訊一覽 - 這部 YouTube 影片介紹了 Android 15 的無邊框措施
- 無邊框和插邊 |撰寫提示 - 這部 YouTube 影片說明如何處理插邊,以便繪製無邊框設計
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- Material Design 元件和版面配置
- 將
CoordinatorLayout
遷移至 Compose - 其他考量