Jetpack ComposeでIMEの表示/非表示に合わせてコンポーネントの位置を変更する
デモ
こういうの
ライブラリ
以下のライブラリを導入します。
implementation 'com.google.accompanist:accompanist-insets:0.23.0'
Accompanist
は、Jetpack Compose
にはまだ実装されていない機能を補完したライブラリ群です。リンクは末尾に掲載しておきます。
実装
まず、AndroidManifest
にandroid:windowSoftInputMode="adjustResize
を追加します。
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
adjustResize
はソフトウェアキーボードの表示スペースを確保し、Activity
のメインウィンドウは動的にサイズが変更されます。このとき他のUIはスクロールできないと全てのコンテンツが見れなくなることがあるため注意しましょう。
どうやら、本来このような設定は不要とのことですが、Jetpack Composeでは、デフォルト設定のstateUnspecified
だとIMEのアニメーションが機能しないようです。
The default value of windowSoftInputMode should work, but Compose does not currently set the flags necessary.
https://google.github.io/accompanist/insets/#ime-animations
次に、上記で設定したActivity
でWindowCompat.setDecorFitsSystemWindows(window, false)
を呼び出します。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
}
}
今回はTextField
の位置を調整するために、Modifier.padding()
を用います。また、この関数の引数にセットするDP
はソフトウェアキーボードの表示/非表示に合わせるために以下のように設定します。(数値はお好みでどうぞ)
val configuration = LocalConfiguration.current
val ime = LocalWindowInsets.current.ime
val padding: Dp by animateDpAsState(
targetValue = if (ime.isVisible) {
// 56.dp
TextFieldDefaults.MinHeight
} else {
// Center
(configuration.screenHeightDp / 2).dp
}
)
animateDpAsState
はtargetValue
が変更されると自動でアニメーションが開始します。
あとは好きなUIにセットするだけです。(デモではTextField
を色々カスタマイズしてます)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
val configuration = LocalConfiguration.current
val ime = LocalWindowInsets.current.ime
val padding: Dp by animateDpAsState(
targetValue = if (ime.isVisible) {
TextFieldDefaults.MinHeight
} else {
(configuration.screenHeightDp / 2).dp
}
)
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(top = padding)
) {
TextField()
}
}
}
}
リンク
windowSoftInputMode
について
Accompanist
について
Discussion