edge-to-edge
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePrerequisites
前提条件
- Project MUST use Android Jetpack Compose.
- Project MUST target SDK 35 or later. If the SDK is lower than 35, increase the SDK to 35.
- 项目必须使用Android Jetpack Compose。
- 项目必须以SDK 35或更高版本为目标。如果SDK版本低于35,请将其升级到35。
Step 1: plan
步骤1:规划
- Locate and analyze all Activity classes to detect which have existing edge-to-edge support. For every Activity without edge-to-edge, plan to make each Activity edge-to-edge.
- In each Activity, Locate and analyze all lists and FAB components to detect which have existing edge-to-edge support. For every component without edge-to-edge support, plan to make each of these components edge-to-edge.
- In each Activity, scan for ,
TextField, orOutlinedTextField. If found, then you MUST verify the IME doesn't hide the input field by following the IME section of this skill.BasicTextField
- 定位并分析所有Activity类,检测哪些已支持边缘到边缘显示。对于每个未支持边缘到边缘的Activity,规划为其添加该支持。
- 在每个Activity中,定位并分析所有列表和FAB组件,检测哪些已支持边缘到边缘显示。对于每个未支持的组件,规划为其添加该支持。
- 在每个Activity中,扫描、
TextField或OutlinedTextField。如果找到这些组件,必须按照本技能中关于IME的部分验证输入法不会遮挡输入框。BasicTextField
Step 2: add edge-to-edge support
步骤2:添加边缘到边缘支持
- Add before
enableEdgeToEdgeinsetContentin each Activity that does not already callonCreate.enableEdgeToEdge - Add in the AndroidManifest.xml for all Activities that use a soft keyboard.
android:windowSoftInputMode="adjustResize"
- 在每个尚未调用的Activity的
enableEdgeToEdge方法中,在onCreate之前添加setContent。enableEdgeToEdge - 在AndroidManifest.xml中,为所有使用软键盘的Activity添加。
android:windowSoftInputMode="adjustResize"
Step 3: apply insets
步骤3:应用内边距
-
The app MUST apply system insets, or align content to rulers, so critical UI remains tappable. Choose only one method to avoid double padding:
- PREFERRED: When available, use s and pass
Scaffoldto the content lambda.PaddingValues
<br />kotlinScaffold { innerPadding -> // innerPadding accounts for system bars and any Scaffold components LazyColumn( modifier = Modifier .fillMaxSize() .consumeWindowInsets(innerPadding), contentPadding = innerPadding ) { /* Content */ } }-
PREFERRED: When available, use the automatic inset handling or padding modifiers in material components.
- Material 3 Components manages safe areas for its own components, including:
TopAppBarSmallTopAppBarCenterAlignedTopAppBarMediumTopAppBarLargeTopAppBarBottomAppBarModalDrawerSheetDismissibleDrawerSheetPermanentDrawerSheetModalBottomSheetNavigationBarNavigationRail
- For Material 2 Components, use the parameter to apply insets manually for
windowInsets,BottomAppBarandTopAppBar. DO NOT apply padding to the parent container; instead, pass insets directly to the App Bar component. Applying padding to the parent container prevents the App Bar background from drawing into the system bar area. For example, forBottomNavigation, choose only one of the following options:TopAppBar- PREFERRED:
TopAppBar(windowInsets = AppBarDefaults.topAppBarWindowInsets) TopAppBar(windowInsets = WindowInsets.systemBars.exclude(WindowInsets.navigationBars))TopAppBar(windowInsets = WindowInsets.systemBars.add(WindowInsets.captionBar))
- PREFERRED:
- Material 3 Components manages safe areas for its own components, including:
-
For components outside a Scaffold, use padding modifiers, such asor
Modifier.safeDrawingPadding().Modifier.windowInsetsPadding(WindowInsets.safeDrawing)<br />kotlinBox( modifier = Modifier .fillMaxSize() .safeDrawingPadding() ) { Button( onClick = {}, modifier = Modifier.align(Alignment.BottomCenter) ) { Text("Login") } } -
For deeply nested components with excessive padding, use(e.g.
WindowInsetsRulers). See the IME section for a code sample.Modifier.fitInside(WindowInsetsRulers.SafeDrawing.current) -
When you need an element (e.g. a custom header or decorative scrim) to equal the dimensions of a system bar, use inset size modifiers (e.g.). See the Lists section for a code sample.
Modifier.windowInsetsTopHeight(WindowInsets.systemBars)
- PREFERRED: When available, use
-
应用必须应用系统内边距,或让内容对齐参考线,以确保关键UI保持可点击状态。请仅选择一种方法以避免重复内边距:
- 推荐方案: 当可用时,使用并将
Scaffold传递给内容lambda。PaddingValues
<br />kotlinScaffold { innerPadding -> // innerPadding包含系统栏和所有Scaffold组件的内边距 LazyColumn( modifier = Modifier .fillMaxSize() .consumeWindowInsets(innerPadding), contentPadding = innerPadding ) { /* Content */ } }-
推荐方案: 当可用时,使用Material组件中的自动内边距处理或内边距修饰符。
- Material 3组件会自行处理自身组件的安全区域,包括:
TopAppBarSmallTopAppBarCenterAlignedTopAppBarMediumTopAppBarLargeTopAppBarBottomAppBarModalDrawerSheetDismissibleDrawerSheetPermanentDrawerSheetModalBottomSheetNavigationBarNavigationRail
- 对于Material 2组件,请使用参数为
windowInsets、BottomAppBar和TopAppBar手动应用内边距。不要为父容器添加内边距;请直接将内边距传递给App Bar组件。为父容器添加内边距会阻止App Bar背景绘制到系统栏区域。例如,对于BottomNavigation,请仅选择以下选项之一:TopAppBar- 推荐方案:
TopAppBar(windowInsets = AppBarDefaults.topAppBarWindowInsets) TopAppBar(windowInsets = WindowInsets.systemBars.exclude(WindowInsets.navigationBars))TopAppBar(windowInsets = WindowInsets.systemBars.add(WindowInsets.captionBar))
- 推荐方案:
- Material 3组件会自行处理自身组件的安全区域,包括:
-
对于Scaffold之外的组件,使用内边距修饰符,如或
Modifier.safeDrawingPadding()。Modifier.windowInsetsPadding(WindowInsets.safeDrawing)<br />kotlinBox( modifier = Modifier .fillMaxSize() .safeDrawingPadding() ) { Button( onClick = {}, modifier = Modifier.align(Alignment.BottomCenter) ) { Text("Login") } } -
对于内边距过大的深层嵌套组件,使用(例如
WindowInsetsRulers)。请查看IME部分的代码示例。Modifier.fitInside(WindowInsetsRulers.SafeDrawing.current) -
当你需要某个元素(如自定义标题栏或装饰性遮罩)与系统栏尺寸相同时,使用内边距尺寸修饰符(例如)。请查看列表部分的代码示例。
Modifier.windowInsetsTopHeight(WindowInsets.systemBars)
- 推荐方案: 当可用时,使用
Adaptive Scaffolds
自适应Scaffold
- manages safe areas for its own components, like the
NavigationSuiteScaffoldorNavigationRail. However, the adaptive scaffolds (e.g.NavigationBar,NavigationSuiteScaffold) don't propagate PaddingValues to their inner contents. You MUST apply insets to individual screens or components (e.g., listListDetailPaneScaffoldor FAB padding) as described in Step 3 . DO NOT applycontentPaddingor similar modifiers to thesafeDrawingPaddingparent. This clips and prevents an edge-to-edge screen.NavigationSuiteScaffold
- 会自行处理其组件的安全区域,如
NavigationSuiteScaffold或NavigationRail。但自适应Scaffold(如NavigationBar、NavigationSuiteScaffold)不会将PaddingValues传递给其内部内容。你必须按照步骤3中的描述,为单个屏幕或组件(如列表的ListDetailPaneScaffold或FAB内边距)应用内边距。不要为contentPadding的父容器应用NavigationSuiteScaffold或类似修饰符,这会裁剪内容并阻止边缘到边缘的全屏显示。safeDrawingPadding
IME
输入法(IME)
- For each Activity with a soft keyboard, check that is set in the AndroidManifest.xml. DO NOT use
android:windowSoftInputMode="adjustResize"because it is deprecated. Then, maintain focus on the input field. Choose one:SOFT_INPUT_ADJUST_RESIZE-
- PREFERRED: Add to the content container. This is preferred over
Modifier.fitInside(WindowInsetsRulers.Ime.current)because it reduces jank and extra padding caused by forgetting to consume insets upstream in the hierarchy.imePadding()
- PREFERRED: Add
-
- Add to the content container. The padding modifier MUST be placed before
imePadding. Do NOT useModifier.verticalScroll()if the parent already accounts for the IME withModifier.imePadding()(e.g.contentWindowInsets). Doing so will cause double padding.contentWindowInsets = WindowInsets.safeDrawing
- Add
-
- 对于每个使用软键盘的Activity,请检查AndroidManifest.xml中是否设置了。请勿使用
android:windowSoftInputMode="adjustResize",因为它已被废弃。然后,保持输入框的焦点。请选择以下方案之一:SOFT_INPUT_ADJUST_RESIZE-
- 推荐方案: 为内容容器添加。相比
Modifier.fitInside(WindowInsetsRulers.Ime.current),该方案更优,因为它能减少因忘记在层级上游消费内边距而导致的卡顿和多余内边距。imePadding()
- 推荐方案: 为内容容器添加
-
- 为内容容器添加。该内边距修饰符必须放在
imePadding之前。如果父容器已通过Modifier.verticalScroll()(例如contentWindowInsets)处理了IME内边距,则请勿使用contentWindowInsets = WindowInsets.safeDrawing,否则会导致重复内边距。Modifier.imePadding()
- 为内容容器添加
-
IMEs with Scaffolds code patterns
结合Scaffold的IME代码规范
RIGHT
正确示例
RIGHT because contains IME insets, which are passed to the
content lambda as .
contentWindowInsetsinnerPaddingkotlin
// RIGHT
Scaffold(contentWindowInsets = WindowInsets.safeDrawing) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.consumeWindowInsets(innerPadding)
.verticalScroll(rememberScrollState())
) { /* Content */ }
}RIGHT because fits the content to the IME insets regardless of
.
fitInsidecontentWindowInsetskotlin
// RIGHT
Scaffold() { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.consumeWindowInsets(innerPadding)
.fitInside(WindowInsetsRulers.Ime.current)
.verticalScroll(rememberScrollState())
) { /* Content */ }
}RIGHT because the default does not contain IME insets, and
applies IME insets:
contentWindowInsetsimePadding()kotlin
// RIGHT
Scaffold() { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.consumeWindowInsets(innerPadding)
.imePadding()
.verticalScroll(rememberScrollState())
) { /* Content */ }
}以下示例正确,因为包含IME内边距,这些内边距会作为传递给内容lambda。
contentWindowInsetsinnerPaddingkotlin
// RIGHT
Scaffold(contentWindowInsets = WindowInsets.safeDrawing) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.consumeWindowInsets(innerPadding)
.verticalScroll(rememberScrollState())
) { /* Content */ }
}以下示例正确,因为无论如何设置,都会让内容适配IME内边距。
contentWindowInsetsfitInsidekotlin
// RIGHT
Scaffold() { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.consumeWindowInsets(innerPadding)
.fitInside(WindowInsetsRulers.Ime.current)
.verticalScroll(rememberScrollState())
) { /* Content */ }
}以下示例正确,因为默认的不包含IME内边距,而会应用IME内边距:
contentWindowInsetsimePadding()kotlin
// RIGHT
Scaffold() { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.consumeWindowInsets(innerPadding)
.imePadding()
.verticalScroll(rememberScrollState())
) { /* Content */ }
}WRONG
错误示例
WRONG because there will be excess padding when the IME opens. IME insets are
applied twice, once with innerPadding, which contains IME insets from the passed
values, and once with :
contentWindowInsetsimePaddingkotlin
// WRONG
Scaffold( contentWindowInsets = WindowInsets.safeDrawing ) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.imePadding()
.verticalScroll(rememberScrollState())
) { /* Content */ }
}WRONG because the IME will cover up the content. Scaffold's default
does NOT contain IME insets.
contentWindowInsetskotlin
// WRONG
Scaffold() { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) { /* Content */ }
}以下示例错误,因为当IME弹出时会出现多余内边距。IME内边距被应用了两次:一次是通过包含IME内边距的(来自传入的值),另一次是通过:
innerPaddingcontentWindowInsetsimePaddingkotlin
// WRONG
Scaffold( contentWindowInsets = WindowInsets.safeDrawing ) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.imePadding()
.verticalScroll(rememberScrollState())
) { /* Content */ }
}以下示例错误,因为IME会遮挡内容。Scaffold默认的不包含IME内边距。
contentWindowInsetskotlin
// WRONG
Scaffold() { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) { /* Content */ }
}IMEs without Scaffolds code patterns
不使用Scaffold的IME代码规范
RIGHT
正确示例
The following code samples WILL NOT cause excessive padding.
kotlin
// RIGHT
Box(
// Insets consumed
modifier = Modifier.safeDrawingPadding() // or imePadding(), safeContentPadding(), safeGesturesPadding()
) {
Column(
modifier = Modifier.imePadding()
) { /* Content */ }
}kotlin
// RIGHT
Box(
// Insets consumed
modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing) // or WindowInsets.ime, WindowInsets.safeContent, WindowInsets.safeGestures
) {
Column(
modifier = Modifier.imePadding()
) { /* Content */ }
}kotlin
// RIGHT
Box(
// Insets not consumed, but irrelevant due to fitInside
modifier = Modifier.padding(WindowInsets.safeDrawing.asPaddingValues()) // or WindowInsets.ime.asPaddingValues(), WindowInsets.safeContent.asPaddingValues(), WindowInsets.safeGestures.asPaddingValues()
) {
Column(
modifier = Modifier
.fillMaxSize()
.fitInside(WindowInsetsRulers.Ime.current)
) { /* Content */ }
}以下代码示例不会导致多余内边距。
kotlin
// RIGHT
Box(
// 内边距已被消费
modifier = Modifier.safeDrawingPadding() // 或imePadding(), safeContentPadding(), safeGesturesPadding()
) {
Column(
modifier = Modifier.imePadding()
) { /* Content */ }
}kotlin
// RIGHT
Box(
// 内边距已被消费
modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing) // 或WindowInsets.ime, WindowInsets.safeContent, WindowInsets.safeGestures
) {
Column(
modifier = Modifier.imePadding()
) { /* Content */ }
}kotlin
// RIGHT
Box(
// 内边距未被消费,但fitInside不受此影响
modifier = Modifier.padding(WindowInsets.safeDrawing.asPaddingValues()) // 或WindowInsets.ime.asPaddingValues(), WindowInsets.safeContent.asPaddingValues(), WindowInsets.safeGestures.asPaddingValues()
) {
Column(
modifier = Modifier
.fillMaxSize()
.fitInside(WindowInsetsRulers.Ime.current)
) { /* Content */ }
}WRONG
错误示例
The following code sample WILL cause excessive padding because IME insets are
applied twice:
kotlin
// WRONG
Box(
// Insets not consumed
modifier = Modifier.padding(WindowInsets.safeDrawing.asPaddingValues()) // or WindowInsets.ime.asPaddingValues(), WindowInsets.safeContent.asPaddingValues(), WindowInsets.safeGestures.asPaddingValues()
) {
Column(
modifier = Modifier.imePadding()
) { /* Content */ }
}以下代码示例会导致多余内边距,因为IME内边距被应用了两次:
kotlin
// WRONG
Box(
// 内边距未被消费
modifier = Modifier.padding(WindowInsets.safeDrawing.asPaddingValues()) // 或WindowInsets.ime.asPaddingValues(), WindowInsets.safeContent.asPaddingValues(), WindowInsets.safeGestures.asPaddingValues()
) {
Column(
modifier = Modifier.imePadding()
) { /* Content */ }
}Navigation Bar Contrast & System Bar Icons
导航栏对比度 & 系统栏图标
-
If the Activity usesfrom
enableEdgeToEdge, you MUST setWindowCompatandisAppearanceLightNavigationBarsto the inverse of the device theme for apps that support light and dark theme so the system bar icons are legible. It's recommended to do this in your theme file. DO NOT do this if the Activities useisAppearanceLightStatusBarsfromenableEdgeToEdgebecause it handles the icon colors automatically.ComponentActivity<br />kotlin// Only use if calling `enableEdgeToEdge` from `WindowCompat`. // Apply to your theme file. @Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { val view = LocalView.current if (!view.isInEditMode) { SideEffect { val window = (view.context as? Activity)?.window ?: return@SideEffect val controller = WindowCompat.getInsetsController(window, view) // Dark icons for Light Mode (!darkTheme), Light icons for Dark Mode controller.isAppearanceLightStatusBars = !darkTheme controller.isAppearanceLightNavigationBars = !darkTheme } } MaterialTheme(content = content) } -
If any screen uses aor a
Scaffoldwith a bottom bar (e.g.,NavigationSuiteScaffold,BottomAppBar), setNavigationBarin the corresponding Activity for SDK 29+. This prevents the system from adding a translucent background to the navigation bar, verifying your bottom bar colors extend to the bottom of the screen.window.isNavigationBarContrastEnforced = false
-
如果Activity使用中的
WindowCompat,你必须为支持亮色和暗色主题的应用设置enableEdgeToEdge和isAppearanceLightNavigationBars为设备主题的反值,以确保系统栏图标清晰可读。建议在主题文件中进行此设置。如果Activity使用isAppearanceLightStatusBars中的ComponentActivity,则无需进行此操作,因为它会自动处理图标颜色。enableEdgeToEdge<br />kotlin// 仅当调用`WindowCompat`中的`enableEdgeToEdge`时使用。 // 应用到你的主题文件中。 @Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { val view = LocalView.current if (!view.isInEditMode) { SideEffect { val window = (view.context as? Activity)?.window ?: return@SideEffect val controller = WindowCompat.getInsetsController(window, view) // 亮色主题使用深色图标(!darkTheme),暗色主题使用亮色图标 controller.isAppearanceLightStatusBars = !darkTheme controller.isAppearanceLightNavigationBars = !darkTheme } } MaterialTheme(content = content) } -
如果任何屏幕使用带有底部栏(如、
BottomAppBar)的NavigationBar或Scaffold,请在对应的Activity中为SDK 29+版本设置NavigationSuiteScaffold。这可以防止系统为导航栏添加半透明背景,确保你的底部栏颜色延伸至屏幕底部。window.isNavigationBarContrastEnforced = false
Lists
列表
- Apply inset padding (like 's
Scaffold) to theinnerPaddingparameter of scrollable components (e.g.contentPadding,LazyColumn). DO NOT apply it as aLazyRowto the list's parent container, as this clips the content and prevents it from scrolling behind the system bars.Modifier.padding() - Create a translucent composable covering the system bar so that the icons are still legible.
kotlin
class SystemBarProtectionSnippets : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// enableEdgeToEdge sets window.isNavigationBarContrastEnforced = true
// which is used to add a translucent scrim to three-button navigation
enableEdgeToEdge()
setContent {
MyTheme {
// Main content
MyContent()
// After drawing main content, draw status bar protection
StatusBarProtection()
}
}
}
}
@Composable
private fun StatusBarProtection(
color: Color = MaterialTheme.colorScheme.surfaceContainer,
) {
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(
with(LocalDensity.current) {
(WindowInsets.statusBars.getTop(this) * 1.2f).toDp()
}
)
.background(
brush = Brush.verticalGradient(
colors = listOf(
color.copy(alpha = 1f),
color.copy(alpha = 0.8f),
Color.Transparent
)
)
)
)
}- 为可滚动组件(如、
LazyColumn)的LazyRow参数应用内边距(如contentPadding的Scaffold)。请勿将其作为innerPadding应用到列表的父容器,这会裁剪内容并阻止其在系统栏后方滚动。Modifier.padding() - 创建一个半透明的可组合组件覆盖系统栏,以确保图标仍然清晰可读。
kotlin
class SystemBarProtectionSnippets : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// enableEdgeToEdge会设置window.isNavigationBarContrastEnforced = true
// 这会为三键导航添加半透明遮罩
enableEdgeToEdge()
setContent {
MyTheme {
// 主内容
MyContent()
// 绘制完主内容后,绘制状态栏遮罩
StatusBarProtection()
}
}
}
}
@Composable
private fun StatusBarProtection(
color: Color = MaterialTheme.colorScheme.surfaceContainer,
) {
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(
with(LocalDensity.current) {
(WindowInsets.statusBars.getTop(this) * 1.2f).toDp()
}
)
.background(
brush = Brush.verticalGradient(
colors = listOf(
color.copy(alpha = 1f),
color.copy(alpha = 0.8f),
Color.Transparent
)
)
)
)
}Dialogs
对话框
If both the following conditions are true, then the Dialog is full screen and
must be made edge-to-edge:
- The contains
DialogProperties.usePlatformDefaultWidth = false - The Dialog calls .
Modifier.fillMaxSize()
To make a full screen Dialog edge-to-edge, set
in the .
decorFitsSystemWindows = falseDialogPropertieskotlin
Dialog(
onDismissRequest = { /* Handle dismiss */ },
properties = DialogProperties(
// 1. Allows the dialog to span the full width of the screen
usePlatformDefaultWidth = false,
// 2. Allows the dialog to draw behind status and navigation bars
decorFitsSystemWindows = false
)
) { /* Content */ }如果同时满足以下两个条件,则该对话框为全屏对话框,必须设置为边缘到边缘显示:
- 中包含
DialogProperties。usePlatformDefaultWidth = false - 对话框调用了。
Modifier.fillMaxSize()
要将全屏对话框设置为边缘到边缘显示,请在中设置。
DialogPropertiesdecorFitsSystemWindows = falsekotlin
Dialog(
onDismissRequest = { /* Handle dismiss */ },
properties = DialogProperties(
// 1. 允许对话框占满屏幕宽度
usePlatformDefaultWidth = false,
// 2. 允许对话框在状态栏和导航栏后方绘制
decorFitsSystemWindows = false
)
) { /* Content */ }Checklist
检查清单
- [ ] Does every call
Activity?enableEdgeToEdge() - [ ] Is set in the
adjustResize?AndroidManifest.xml - [ ] Does every ,
TextField, orOutlinedTextFieldhave a parent withBasicTextField,imePadding(),fitInside,Modifier.safeDrawingPadding(),Modifier.safeContentPadding(), orModifier.safeGesturesPadding()set tocontentWindowInsetsorWindowInsets.safeDrawing?WindowInsets.ime - [] Does the first and last list item draw away from the system bars by passing insets to ?
contentPadding - [] Do FABs draw above the navigation bars by either being inside a Scaffold or by applying ?
Modifier.safeDrawingPadding() - [] Does the project build? Run to be sure.
./gradlew build
- 每个都调用了
Activity吗?enableEdgeToEdge() - AndroidManifest.xml中是否设置了?
adjustResize - 每个、
TextField或OutlinedTextField的父容器是否添加了BasicTextField、imePadding()、fitInside、Modifier.safeDrawingPadding()、Modifier.safeContentPadding(),或者将Modifier.safeGesturesPadding()设置为contentWindowInsets或WindowInsets.safeDrawing?WindowInsets.ime - 列表的第一个和最后一个项是否通过传递内边距给来避开系统栏?
contentPadding - FAB是否通过置于Scaffold内或应用来显示在导航栏上方?
Modifier.safeDrawingPadding() - 项目能否正常构建?运行以确认。
./gradlew build