Android 15 に備えてテキスト入力がある画面を edge-to-edge 対応する

Android 15からedge-to-edgeが強制されるようになります。

https://developer.android.com/about/versions/15/behavior-changes-15?hl=ja

現在、Android Studioで新規プロジェクトを作成するとedge to edge対応のサンプルが作られるように、ひとまず従来と同等の表示をさせるの難しくありません。
しかし、以下のように、テキスト入力がある画面で、画面下部に送信などのボタンがある画面において、ソフトウェアキーボードが表示されたときは、それに合わせてボタン部分もせり上がらないと一度キーボードを非表示にしないとボタンが押せないという状態になってしまいます。

|||
|--|--|
|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/714eb0b2-2783-c3ce-7ba8-54d033727c55.png)|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/e57b92b8-93dd-33dd-434f-01d1a796a907.png)|

従来であれば、AndroidManifest.xmlで`android:windowSoftInputMode="adjustResize"`を指定するだけで対応できました。

```AndroidManifest.xml
<activity
    android:name=".MainActivity"
    android:windowSoftInputMode="adjustResize"
    android:exported="true"
    >
```

標準的なedge to edge対応のActivityの場合

```MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    enableEdgeToEdge()
    val binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
    ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
        val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
        v.setPadding(
            systemBars.left,
            systemBars.top,
            systemBars.right,
            systemBars.bottom,
        )
        insets
    }
}
```

`android:windowSoftInputMode="adjustResize"`を設定していても以下のように、キーボードに隠れてしまいます。

|||
|--|--|
|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/781d599c-e2d6-b698-906a-91a9497ddca1.png)|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/10ce84c7-7922-4145-08f8-6098264b6020.png)|

# `OnApplyWindowInsetsListener`にてimeのinsetsを含める

ほとんどの場合はこちらの対応で十分かと思います、テンプレート通りだと、`OnApplyWindowInsetsListener`にて、systemBarsのinsetsをpaddingに設定していますが、ここでimeのinsetsも含めて設定するようにします。
imeのinsetsはsystemBarsのinsetsを除外したものではないので、maxOfで大きな方の値を設定するようにします。
本来であれば上下左右の設定をすべきかもしれませんが、bottomだけ変更しています。

```MainActivity.kt
ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
    val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
    v.setPadding(
        systemBars.left,
        systemBars.top,
        systemBars.right,
        maxOf(systemBars.bottom, ime.bottom),
    )
    insets
}
```

# `WindowInsetsAnimationCallback`を利用する

もう一つの方法、API 30から`WindowInsetsAnimationCallback`が使えるようになっており、これを使うことで、IMEが表示されるアニメーションに合わせて処理ができるようになっています。ViewCompatを使うことで過去のバージョンでも利用できます。
以下のように、追加のpaddingを設定することで、ソフトキーボードの上にボタンがくるようにレイアウトを変更することができます。

```MainActivity.kt
ViewCompat.setWindowInsetsAnimationCallback(
    binding.main,
    object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {
        override fun onProgress(
            insets: WindowInsetsCompat,
            runningAnimations: MutableList<WindowInsetsAnimationCompat>,
        ): WindowInsetsCompat {
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
            binding.buttonArea.updatePadding(
                bottom = (ime.bottom - systemBars.bottom).coerceAtLeast(0)
            )
            return insets
        }
    })
```

|||
|--|--|
|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/b1de87e1-bf6c-9507-1b1d-466c83add639.png)|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/9a06fd56-da88-057a-6e55-6dd2a921c4d9.png)|

以上です