Avance.Lab

技術紹介

【新機能探訪】Androidの予測型「戻る」ジェスチャー

公開日:2023.07.14 更新日:2023.07.14

tag: スマートデバイス

こんにちは、KNSKです。
よろしくお願いします。

今回は Android 13 (14) の新機能である 予測型「戻る」ジェスチャーについて
開発者目線で紹介します。

以降の内容は Google Pixel 7a(Android 14 Beta 4)を使用して動作確認しました。

予測型「戻る」ジェスチャー とは

Androidでは、画面の左右の端から内側にスワイプすることで、アプリを終了させたり前の画面に戻ることができます。
※ ジェスチャーナビゲーションを使用している場合に限ります。

この操作を「戻る」ジェスチャーと言います。

なお、指を離さずに逆方向にスワイプすると操作をキャンセルできます。

Android13で「戻る」ジェスチャーの操作中にアニメーションが表示されるようになり、操作がもたらす結果を予測できるようになりました。
この機能を 予測型「戻る」ジェスチャーと言います。

Android13ではアニメーションが表示されるタイミングはアプリが終了するときのみですが、
Android14ではアプリ内の前の画面(Activity)に戻るときにも表示されるようになります。

なお、予測型「戻る」ジェスチャーを動作させるためには、
開発者向けオプションの設定項目をONにする必要があります。
Android13のデフォルトはOFFになっていますが、Android14のデフォルトはONになるようです。

また、アプリ自体も予測型「戻る」ジェスチャーに対応するように作成されている必要があります。

ちなみに予測型「戻る」ジェスチャーは英語では predictive back gesture と言います。

対応アプリ開発方法

予測型「戻る」ジェスチャーに対応するアプリを作成する方法を記載します。
compileSdk / targetSdkは34(Android14)を使用します。

オプトイン

予測型「戻る」ジェスチャーに対応させたい画面(Activity)に対して
android:enableOnBackInvokedCallback=true を設定します。
特にカスタマイズが不要であれば、この対応だけでアニメーションが表示されるようになります。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        ...
        <activity
            ...
            android:enableOnBackInvokedCallback="true"
            ... />
        ...
    </application>
</manifest>

イベントハンドリング

「戻る」操作が実行されたときに何らかのUI表示を伴う処理を実行したい場合は
イベントハンドリングが必要となります。
OnBackPressedCallback を使用することで「戻る」ジェスチャーに関するイベントをハンドルできます。
※ AndroidX Activity の1.8.0-alpha01以上が必要となります。 

class MainActivity : BaseActivity() {
    ...
    private val callback = object: OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            // ダイアログ表示
            AlertDialog.Builder(this@MainActivity)
                .setTitle("確認")
                .setMessage("アプリを終了しますか")
                .setPositiveButton("OK") { _, _ ->
                    finish()
                }
                .setNegativeButton("Cancel") { _, _ ->
                }
                .show()
        }

        override fun handleOnBackStarted(backEvent: BackEventCompat) {
            super.handleOnBackStarted(backEvent)
        }

        override fun handleOnBackProgressed(backEvent: BackEventCompat) {
            super.handleOnBackProgressed(backEvent)
            binding.textView.text = String.format("Progress = %.5f", backEvent.progress)
        }

        override fun handleOnBackCancelled() {
            super.handleOnBackCancelled()
            binding.textView.text = "Canceled"
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        onBackPressedDispatcher.addCallback(callback)
        callback.isEnabled = binding.switchCustomize.isChecked
        binding.switchCustomize.setOnCheckedChangeListener { _, b ->
            callback.isEnabled = b
        }
        ....
    }
    ...
}

Callbackが有効な場合は標準のアニメーションは表示されません。アニメーションが必要な場合はprogressの値を基に実装することになります。
この例ではスイッチでCallbackの有効/無効を切り替えています。

handleOnBackPressed が「戻る」操作が確定したときのイベントです。
この例ではダイアログを表示しています。

アプリ内遷移アニメーションのカスタマイズ

overrideActivityTransition を使用することで、Activity間のアニメーションをカスタマイズできます。

class SubActivity : BaseActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            overrideActivityTransition(OVERRIDE_TRANSITION_OPEN, R.anim.enter_from_right, R.anim.exit_to_left)
            overrideActivityTransition(OVERRIDE_TRANSITION_CLOSE, R.anim.enter_from_left, R.anim.exit_to_right)
        }
        ....
    }
    ...
}

この例のように左右にスライドするアニメーションを使用すると、スワイプの向きによっては違和感が生じるため注意が必要だと思われます。

最後に

画面終了時にダイアログ表示などのUI表示を伴う処理を実行しているアプリの場合、
対応が煩雑になったり、この機能の恩恵を受けにくくなるため、そういった仕様は最低限にすべきだと思われます。

私は未だに3ボタンナビゲーションを愛用していますが、
ジェスチャーナビゲーションに切り替えるときが来たかもしれません…。

参考

KNSK

主にスマホアプリ開発を担当しています。
現在Flutterに挑戦中です。

関連記事