Community编程与开发github.com

wasey-rao/kmp-edge-to-edge

在 Compose Multiplatform 中为 Android 和 iOS 实现边缘到边缘布局——按平台启用,配合 Scaffold 处理窗口插边、列表、底部栏、键盘、屏幕刘海、系统栏图标对比度以及屏幕边缘广告横幅。适用于构建任何屏幕脚手架、修复被状态栏、导航栏、刘海或键盘遮挡的内容,或针对 Android 15 及更高版本开发时使用。

kmp-edge-to-edge 是什么?

此技能针对 Compose Multiplatform 项目提供全面的边缘到边缘布局解决方案。Android 从 SDK 35 开始强制要求边缘到边缘布局,SDK 36 后无法选择退出;iOS 应用也预期在状态栏和 Home Indicator 下方绘制内容。该技能指导开发者如何在 Android 的 `MainActivity` 中调用 `enableEdgeToEdge()` 并配置清单,在 iOS 的 `ContentView.swift` 中使用 `ignoresSafeArea()`,从而让 Compose 完全控制屏幕区域。核心使用 `Scaffold` 及其 `innerPadding` 自动处理系统栏插边,对于非 Scaffold 场景则利用 `WindowInsets.safeDrawing` 手动应用内边距。特别推荐的做法包括:使用 `imePadding()` 确保键盘弹出时内容仍然可见;全出血内容(如图片、视频)忽略插边,仅将控制元素垫高;广告横幅应放在 `bottomBar` 插槽中以保持布局稳定;并通过适当的 `SystemBarStyle` 管理系统栏图标对比度。该技能适用于 Cursor、Claude Code 等 AI 编码工具,也适合直接阅读 SKILL.md 文档。

兼容平台~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 应用也预期在状态栏和 Home Indicator 下方绘制内容。从一开始就将每个屏幕构建为边缘到边缘。

规则:背景在系统栏下方绘制;内容和控件通过插边获得内边距。

启用它

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

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

在清单中,为 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 插槽中,位于导航栏插边之上,并保留其高度,以便内容不会跳动。绝不要将横幅置于手势栏下方或与导航控件重叠;这既是布局错误,也是广告政策问题。

每个屏幕的检查清单

  • 背景到达顶部和底部的物理边缘。
  • 没有文本或控件位于状态栏、刘海、导航栏或 Home Indicator 下方。
  • 最后一个列表项可以在底部栏上方完全滚动。
  • 获得焦点的文本字段在键盘打开时保持可见。
  • 在横向模式(刘海在侧面)和深色主题下显示正确。
  • 插边仅应用一次,没有重复。

如果安装了 Google 的 edge-to-edge 技能,请使用它进行针对 Android 的进一步故障排除。

相关技能