Android 平台負責繪製系統 UI,例如 狀態列和導覽列無論 使用者正在使用的應用程式。
WindowInsets
提供系統相關資訊
UI 可確保應用程式繪製在正確的區域,且 UI 不會遭到遮蓋
由系統 UI 產生
![採用無邊框設計,在系統資訊列後方繪製](https://developer.android.com/static/develop/ui/compose/images/layouts/insets/e2e-intro.gif?authuser=0000&hl=zh-tw)
在 Android 14 (API 級別 34) 以下版本中,應用程式的 UI 不會在以下之下繪製 系統資訊列和螢幕凹口。
在 Android 15 (API 級別 35) 以上版本中,應用程式會在系統下方繪製 應用程式指定 SDK 35 後,就會呈現凹口。如此一來 順暢的使用者體驗,並充分發揮應用程式的功用 可用的視窗空間
在系統 UI 後方顯示內容稱為「無邊框設計」。在這方面 您將進一步瞭解不同類型的插邊、採用無邊框設計的方法 以及如何使用插邊 API 為使用者介面建立動畫效果,並確保應用程式的內容 不會遭系統 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
可以確保 內容沒有重疊的視覺效果,也沒有重疊的手勢。
插邊設定
如要讓應用程式完全控制繪製內容的位置,請遵循下列設定 100 萬步的訓練如果沒有執行上述步驟,您的應用程式可能會在畫面背後繪製黑色或純色 系統 UI,或是不要與螢幕鍵盤同步動畫。
- 指定 SDK 35 以上版本,在 Android 15 以上版本中強制採用無邊框設計。您的應用程式 會在系統 UI 後方顯示。如要調整應用程式的 UI,您可以處理 插邊。
- 您可以視需要呼叫
enableEdgeToEdge()
,Activity.onCreate()
,可讓應用程式自動採用無邊框設計 Android 版本。 在活動的
android:windowSoftInputMode="adjustResize"
AndroidManifest.xml
個項目。這項設定可讓應用程式接收 做為插邊,可用來設定內容的位置和版面配置 。<!-- 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
當 Activity 控制所有插邊後,您就可以使用 Compose API 可確保內容不會遭到遮蓋及可互動的元素 與系統 UI 重疊這些 API 也會將您的應用程式版面配置與 插邊變更。
舉例來說,這是將插邊套用至內容的最基本方法 您整個應用程式的作業流程
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { Box(Modifier.safeDrawingPadding()) { // the rest of the app } } }
這段程式碼會將 safeDrawing
視窗插邊做為邊框間距,
整個應用程式的內容雖然這樣能確保可互動元素
這也表示應用程式不會在後端
進而實現無邊框效果為了充分利用
視窗,您需要在每個畫面上,微調插邊套用的位置
或是根據元件建構不同元件
這些插邊類型全都會自動使用 IME 動畫製作動畫 已向後移植至 API 21因此,凡是使用這些插邊的版面配置 而且會在插邊值變更時自動產生動畫效果
使用這些插邊類型來調整可組合函式的主要方式有兩種 版面配置:邊框間距修飾符和插邊大小修飾符。
邊框間距修飾符
Modifier.windowInsetsPadding(windowInsets: WindowInsets)
會套用
將特定視窗插邊設為邊框間距,運作原理與 Modifier.padding
相同。
舉例來說,Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
就會套用
安全繪圖插邊做為邊框間距
另也有數種內建公用程式方法適用於最常見的插邊類型。
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
與
輸入法列的底部資訊列進入動畫後,
TextField
的無邊框延遲資料欄。要完成上述行為,
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
或固定高度
空格字元:
@OptIn(ExperimentalLayoutApi::class) 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 的階段之間有特殊的關係 撰寫
插邊值是在組成階段之後更新,但更新前 版面配置階段這表示讀取組合中插邊的值 通常會使用影格延遲的插邊值。內建 本頁說明的修飾符的設計是為了讓系統使用 直到版面配置階段為止,確保使用插邊值 相同的影格也會同步更新
使用 WindowInsets
的鍵盤輸入法編輯器動畫
您可以將 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") } } }
![動畫顯示的是上下捲動的 UI 元素,以便使用鍵盤](https://developer.android.com/static/develop/ui/compose/images/interop-keyboard.gif?authuser=0000&hl=zh-tw)
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
。
資源
- Now in Android:完全使用 Kotlin 和 Jetpack Compose 建構的 Android 應用程式,功能齊全。
- 處理 Android 15 強制採用的無邊框措施 - 這個程式碼研究室會逐步說明 Android 15 的無邊框措施
- 改善 Android 應用程式體驗的 3 個方面:Edge to Edge、預測返回和資訊一覽 - 這部 YouTube 影片介紹了 Android 15 的無邊框措施
- 無邊框和插邊 |撰寫提示 - 這部 YouTube 影片說明如何處理插邊,以便繪製無邊框設計
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- Material Design 元件和版面配置
- 將
CoordinatorLayout
遷移至 Compose - 其他考量