Community程式設計與開發github.com

wasey-rao/kmp-edge-to-edge

在 Compose Multiplatform 中實現 Android 與 iOS 的邊到邊佈局,包含各平台啟用方式、WindowInsets 搭配 Scaffold、列表、底部欄、鍵盤、螢幕缺口、系統列圖示對比度以及全螢幕廣告橫幅。適用於任何畫面建構、修正內容被狀態列、導覽列、缺口或鍵盤遮擋的情況,或針對 Android 15 以上版本開發時使用。

kmp-edge-to-edge 是什麼?

這個技能詳細說明了如何在 Compose Multiplatform 專案中實作邊到邊 (edge-to-edge) 佈局,適用於 Android 與 iOS 平台。隨著 Android 強制要求 SDK 35 以上應用程式採用邊到邊佈局,且 Android 36 完全移除退出選項,加上 iOS 應用程式預期需在狀態列與首頁指示器下方繪製內容,這項技能能協助開發者從一開始就正確建構每個畫面。核心原則是:背景在系統列後方繪製,而內容與控制項則透過內邊距 (insets) 進行偏移。技能內容涵蓋如何在 Android 的 `MainActivity` 中呼叫 `enableEdgeToEdge()`、在 iOS 的 `ContentView.swift` 中使用 `ignoresSafeArea()`,以及如何善用 `Scaffold` 搭配 `innerPadding` 自動處理狀態列與導覽列的內邊距。對於無 Scaffold 的畫面,則建議使用 `WindowInsets.safeDrawing` 或 `safeContent`。此外,技能也詳細說明了鍵盤處理 (`imePadding`)、全出血內容 (圖片、地圖、影片)、系統列圖示對比度設定、廣告橫幅的正確擺放方式,並提供一份完整的畫面檢查清單,確保開發者不會遺漏任何細節。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/wasey-rao/kmp-agent-studio/tree/HEAD/kmp-studio/skills/kmp-edge-to-edge

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Compose Multiplatform 中的邊到邊佈局

Android 對目標 SDK 35 及更高版本的應用程式強制實施邊到邊佈局,且在 SDK 36 中無法選擇退出。iOS 應用程式預期在狀態列與首頁指示器下方繪製內容。從一開始就以邊到邊方式建構每個畫面。

規則:背景在系統列後方繪製;內容與控制項透過內邊距 (insets) 進行偏移。

啟用方式

Android(位於 androidApp 中的 MainActivity),在 setContent 之前:

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

在 manifest 中,為 activity 設定 android:windowSoftInputMode="adjustResize",讓 IME 內邊距能夠傳遞到 Compose。

iOS(ContentView.swift):讓 Compose 擁有整個畫面,否則 SwiftUI 會先套用安全區域,導致 Compose 看到的內邊距為零。

ComposeView().ignoresSafeArea()

Scaffold 完成大部分工作

Scaffold(
    topBar = { TopAppBar(title = { Text(title) }) },          // 為狀態列自行填充內邊距
    bottomBar = { NavigationBar { /* ... */ } },              // 為導覽列自行填充內邊距
) { innerPadding ->
    LazyColumn(
        contentPadding = innerPadding,                         // 內容在列下方滾動
        modifier = Modifier.fillMaxSize(),
    ) { /* items */ }
}
  • 始終使用 innerPadding。對於列表,將其作為 contentPadding 傳遞,使項目能在半透明列後方滾動;對於不可滾動的內容,請使用 Modifier.padding(innerPadding)。
  • Material 3 的列會自行消耗其內邊距。不要在 TopAppBar 之上額外添加 statusBarsPadding()。
  • 巢狀 Scaffold 會使內邊距加倍。為內層 Scaffold 設定 contentWindowInsets = WindowInsets(0),或在外層內容上套用 consumeWindowInsets(innerPadding)。

沒有 Scaffold 的畫面

Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {   // 背景填滿畫面
    Column(Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.safeDrawing)) { /* content */ }
}

WindowInsets.safeDrawing 涵蓋狀態列、導覽列、螢幕缺口與鍵盤。當手勢操作重要時,請使用 safeContent。內邊距的填充僅需在最上層負責內容的層級套用一次,切勿同時在父層與子層套用。

鍵盤

  • 輸入畫面:在可滾動容器上使用 Modifier.imePadding(),或使用已包含 IME 的 safeDrawing。
  • 必須位於鍵盤上方的底部按鈕:將其放入 Scaffold 的 bottomBar 中,並搭配 Modifier.imePadding(),或使用 WindowInsets.ime.union(WindowInsets.navigationBars)。
  • 讓內容可滾動,以便聚焦的輸入欄位能夠進入視野。

全出血內容

圖片、地圖、影片與相機預覽應忽略內邊距,填滿整個畫面。在頂層疊加控制項,並僅對控制項使用 WindowInsets.safeDrawing 進行內邊距填充。

系統列圖示對比度

系統列是透明的,因此圖示對比度由您負責。在 Android 上,enableEdgeToEdge() 會根據系統主題選擇淺色或深色圖示;如果應用程式有自己的主題切換功能,請在主題變更時以相符的 SystemBarStyle 再次呼叫該方法。在三按鈕導覽模式下,Android 會添加半透明遮罩;除非底部欄已提供實色背景,否則請保留此遮罩。

廣告橫幅

底部橫幅應放入 Scaffold 的 bottomBar 插槽中,位於導覽列內邊距上方,並保留其高度,使內容不會跳動。切勿讓橫幅位於手勢列下方或與導覽控制項重疊,這不僅是佈局錯誤,也違反廣告政策。

每個畫面的檢查清單

  • 背景抵達頂端與底端的物理邊緣。
  • 沒有文字或控制項位於狀態列、螢幕缺口、導覽列或首頁指示器下方。
  • 最後一個列表項目可完整滾動至底部欄上方。
  • 在鍵盤開啟時,聚焦的文字輸入欄位保持可見。
  • 在橫向模式(缺口在側邊)與深色主題下顯示正確。
  • 內邊距僅套用一次,未重複加倍。

如果已安裝 Google 的 edge-to-edge 技能,請使用它進行 Android 專屬的進一步疑難排解。

相關技能