这是我参与更文挑战的第5天,活动详情查看: 更文挑战
本文翻译自 Accompanist 官方文档 - Insetshtml
目前有一个正在进行的 Jetpack Compose中文手册 项目,旨在帮助开发者更好的理解和掌握Compose框架,目前仍还在开荒中,欢迎你们进行关注与加入! 这篇文章由本人翻译撰写,目前已经发布到该手册中,欢迎进行查阅。java
Jetpack Compose 的 Insets 采用了 View 系统中 Insetter 组件库的设计理念,使其能够在 composables 中被使用。android
为了能在你的 composables 中使用 Insets , 你须要使用 ProvideWindowInsets
方法并将你的视图内容声明在尾部lambda中。这步操做一般要在你的composable层级的顶部附近进行。git
setContent {
MaterialTheme {
ProvideWindowInsets {
// your content
}
}
}
复制代码
⚠️ 为了使你的 view 层级可以获取到 Insets, 你须要确保在你Activity中使用 WindowCompat.setDecorFitsSystemWindows(window, false)
。若是你还想为你的系统状态栏设置颜色,可使用Accompanist组件库提供的系统UI控制器组件来完成。github
经过使用 ProvideWindowInsets
方法将容许本组件在 content 中设置一个 OnApplyWindowInsetsListener,这个Listener将会被用来更新 LocalWindowInsets
这个 CompositionLocal。api
LocalWindowInsets
持有了一个 WindowInsets
实例,其中包含了各类 WindowInsets types 数值信息,例如状态栏、导航栏、输入法等。你一般能够像这样使用这些数值信息。微信
Composable
fun ImeAvoidingBox() {
val insets = LocalWindowInsets.current
// 切记,这些信息都是px单位,使用时要根据需求转换单位
val imeBottom = with(LocalDensity.current) { insets.ime.bottom.toDp() }
Box(Modifier.padding(bottom = imeBottom))
}
复制代码
可是本组件一样也提供了一些易于使用的Modifier。markdown
本组件提供了两种 Modifier 类型用于轻松适配特定 insets 的 padding 与 size.app
使用 Padding Modifier 将容许为你的 composable 施加 padding 来适配一些特定的 insets,当前提供了以下几种扩展方法。框架
这些方法一般会被用来将 composable 移出系统状态栏或导航栏等,FloatingActionButton 就是一个典型的例子,一般咱们都但愿将这个悬浮按钮移动至系统导航栏上方, 不但愿被系统导航栏遮盖。
FloatingActionButton(
onClick = { /* TODO */ },
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp) // normal 16dp of padding for FABs
.navigationBarsPadding() // Move it out from under the nav bar
) {
Icon(imageVector = Icons.Default.Add, contentDescription = null)
}
复制代码
经过 Size Modifier 将容许为你的 composable 施加 size 来适配一些特定的 Insets,当前提供了以下几种扩展方法。
我门一般可让 composable 为系统栏提供背景,相似以下。
Spacer(
Modifier
.background(Color.Black.copy(alpha = 0.7f))
.statusBarsHeight() // Match the height of the status bar
.fillMaxWidth()
)
复制代码
Compose 提供了 PaddingValues 的理念,该数据类包含着全部要被施加的 padding 信息(相似于一个 Rect)。一般会被用于一些容器类型 composables,例如为 LazyColumn 设置内容 padding。
你可能须要使用某个具体 Inset 信息做为内容 padding,因此本组件提供了 rememberInsetsPaddingValues() 扩展方法用于将 Inset 转化为 PaddingValues,下面的例子中就获取了系统栏Inset信息。
LazyColumn(
contentPadding = rememberInsetsPaddingValues(
insets = LocalWindowInsets.current.systemBars,
applyTop = true,
applyBottom = true,
)
) {
// content
}
复制代码
对于更复杂的场景,能够查阅例子 EdgeToEdgeLazyColumn
不幸的是,目前大多数 Compose 所提供的 Material 风格的 Layout 还不支持使用内容 padding,这意味着下面的代码可能不会产生与你的预期相同的结果。
// 😥 This likely doesn't do what you want
TopAppBar(
// content
modifier = Modifier.statusBarsPadding()
)
复制代码
为了应对这种状况,咱们提供了 insets-ui
这个兄弟组件库,其中包含了经常使用布局,并增长了一个名为 contentPadding
的参数。下面的例子就是为 TopAppBar 提供状态栏的Inset信息做为内容的 padding。
import com.google.accompanist.insets.ui.TopAppBar
TopAppBar(
contentPadding = rememberInsetsPaddingValues(
insets = LocalWindowInsets.current.statusBars,
applyStart = true,
applyTop = true,
applyEnd = true,
)
) {
// content
}
复制代码
这个兄弟组件库还提供了Scaffold的修改版,经过在content中绘制顶部和底部栏,更好地支持边靠边的布局。
Scaffold(
topBar = {
// We use TopAppBar from accompanist-insets-ui which allows us to provide
// content padding matching the system bars insets.
TopAppBar(
title = { Text(stringResource(R.string.insets_title_list)) },
backgroundColor = MaterialTheme.colors.surface.copy(alpha = 0.9f),
contentPadding = rememberInsetsPaddingValues(
LocalWindowInsets.current.statusBars,
applyBottom = false,
),
)
},
bottomBar = {
// We add a spacer as a bottom bar, which is the same height as
// the navigation bar
Spacer(Modifier.navigationBarsHeight().fillMaxWidth())
},
) { contentPadding ->
// We apply the contentPadding passed to us from the Scaffold
Box(Modifier.padding(contentPadding)) {
// content
}
}
复制代码
有关库中提供的其余布局的列表,请参见 API 文档。
接下来的功能还在试验中,须要开发者选择性使用。
本组件库当前试验性支持 WindowInsetsAnimations, 这将容许你的UI内容能够根据Insets动画发生改变,例如当软键盘弹出或关闭时, imePadding()
或 navigationBarsWithImePadding()
在这种场景下就能够被使用了。 在 API >= 21 的设备上,不管 WindowInsetsAnimationCompat 是否工做,在任意时刻都进行使用。
为了可以使用Insets动画,你须要一个使用 ProvideWindowInsets
的重载方法,而且设置 windowInsetsAnimationsEnabled = true
ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
// content
}
复制代码
你可以像这样使用 navigationBarsWithImePadding()
OutlinedTextField(
// other params,
modifier = Modifier.navigationBarsWithImePadding()
)
复制代码
能够查阅例子 ImeAnimationSample
若是你但愿使用 Insets 动画支持软键盘动画,你须要确保在 AndroidManifest 清单中配置当前 Activity 的 windowSoftInputMode
属性为 adjustResize
。
<activity
android:name=".MyActivity"
android:windowSoftInputMode="adjustResize">
</activity>
复制代码
windowSoftInputMode
默认值应该也有效,可是Compose当前没有设置必要的标识 (详情看 这里)
本组件库已经支持经过手势操做来控制软键盘,这将容许你的可滚动的组件将软键盘拉进或拉出屏幕,对于这种嵌套手势滑动可使用内置的 NestedScrollConnection 接口进行实现,本组件提供了 rememberImeNestedScrollConnection() 方法直接获取这种软键盘动画场景的嵌套手势滑动实现类。
⚠️ 此功能仅在 API >= 30 的设备上才能正常运行。
// Here we're using ScrollableColumn, but it also works with LazyColumn, etc.
ScrollableColumn(
// We use the nestedScroll modifier, passing in the
// the connection from rememberImeNestedScrollConnection()
modifier = Modifier.nestedScroll(
connection = rememberImeNestedScrollConnection()
)
) {
// list content
}
复制代码
能够查阅例子 ImeAnimationSample
repositories {
mavenCentral()
}
dependencies {
implementation "com.google.accompanist:accompanist-insets:<version>"
// If using insets-ui
implementation "com.google.accompanist:accompanist-insets-ui:<version>"
}
复制代码
每一个版本能够在 快照仓库 中被找到,每次提交时都会更新。
若是你发现运行时出现了一些问题,这里有一个错误清单能够查阅。
WindowCompat.setDecorFitsSystemWindows(window, false)
。除非你这么作了,不然 DecorView 将消费这些insets,他们的信息不回被分配到 content 中。windowSoftInputMode
属性被设置为 adjustResize
。不然 IME 的可见性变化将不会做为Insets 变化而发送。.Fullscreen
主题) 。当发现 adjustResize
没有正常工做,请 查阅文档 以了解替代方案。ProvideWindowInsets
(或 ViewWindowInsetObserver) ,你须要关闭 Insets 的消费。当执行 ProvideWindowInsets
(或 ViewWindowInsetObserver) 时会彻底消费全部通过的 Insets。在Activity与其中的Fragment同时使用 ProvideWindowInsets
(或 ViewWindowInsetObserver) 时意味着Activity将获取到 Insets,可是Fragment将不回,为了禁用消费须要设置 ProvideWindowInsets
方法参数 consumeWindowInsets = false
或者使用 ViewWindowInsetObserver.start()
。本文同步已发表于微信公众号,搜索
Jetpack Compose 博物馆
便可关注