這是我參與更文挑戰的第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 博物館
便可關注