予測型「戻る」アニメーションのサポートを追加する

システムの「戻る」API を使用する場合は、アプリ内アニメーションの受け取りをオプトインし、カスタム遷移をサポートすることができます。

動画 1: 予測型「戻る」アニメーション

オプトインすると、アプリは「ホームに戻る」、アクティビティ間、タスク間のアニメーションを表示します。

また、マテリアル コンポーネントの依存関係を MDC Android の v1.10.0 にアップグレードし、次のようなマテリアル コンポーネント アニメーションを受け取ることもできます。

詳しくは、GitHub のマテリアル コンポーネントのデベロッパー ガイダンスをご覧ください。

この動画では、Android 設定アプリを使用して、アクティビティ間と「ホームに戻る」の予測型「戻る」アニメーションの簡単な例を紹介します。

  1. アニメーションでは、ユーザーは後方にスワイプして前の設定画面に戻ります(アクティビティ間アニメーションの例)。
  2. 前の画面で、ユーザーが 2 回目のスワイプを始めると、ホーム画面のプレビューが壁紙とともに表示されます(「ホームに戻る」アニメーションの例)。
  3. ユーザーが右にスワイプし続けると、ウィンドウがホーム画面のアイコンまで縮小するアニメーションが表示されます。
  4. これで、ユーザーは完全にホーム画面に戻ります。

詳しくは、予測型「戻る」ジェスチャーのサポートを追加するをご覧ください。

カスタムのアプリ内遷移とアニメーションを追加する

予測型「戻る」ジェスチャーを使用して、カスタムのアプリ内プロパティ アニメーションと遷移、カスタムのアクティビティ間アニメーション、カスタムのフラグメント間アニメーションを作成できます。

Progress API を使用してカスタム遷移を追加する

AndroidX Activity 1.8.0-alpha01 以降では、Predictive Back Progress API を使用して、アプリ内の予測型「戻る」ジェスチャーのカスタム アニメーションを開発できます。Progress API はビューのアニメーション化に役立ちますが、フラグメント間の遷移をアニメーション化する際には制限があります。OnBackPressedCallback 内に handleOnBackProgressedhandleOnBackCancelledhandleOnBackStarted メソッドを導入し、ユーザーが後方にスワイプしている間にオブジェクトをアニメーション化するようにしました。これらのメソッドは、システムで提供されるデフォルトのアニメーションやマテリアル コンポーネント アニメーション以上のカスタマイズが必要な場合に使用します。

ほとんどのアプリでは、下位互換性のある AndroidX API が使用されることが想定されますが、OnBackAnimationCallback インターフェース内には、Android 14 デベロッパー プレビュー 1 以降でテストできる同様のプラットフォーム API もあります。

AndroidX の遷移で Progress API を使用する

Android 14 以降では、AndroidX Transitions 1.5.0-alpha01 以降で Progress API を使用して、予測型「戻る」遷移を作成できます。

  1. ユーザーが後方にスワイプしたときに遷移を再生するには、beginDelayedTransition ではなく TransitionManager#controlDelayedTransition を使用します。
  2. handleOnBackStarted 内に遷移を作成します。
  3. currentFractionBackEvent.progress に関連付けることで、handleOnBackProgressed 内の「戻る」イベントで遷移を再生します。これにより、ユーザーが過去にスワイプした距離が開示されます。
  4. ユーザーが handleOnBackPressed で「戻る」操作を確定したら、遷移を終了します。
  5. 最後に、handleOnBackCancelled 内で遷移の状態をリセットします。

次の動画、Kotlin コード、XML は、OnBackPressedCallback で実装された 2 つのボックス間のカスタム遷移を示しています。

    class MyFragment : Fragment() {

    val transitionSet = TransitionSet().apply {
        addTransition(Fade(Fade.MODE_OUT))
        addTransition(ChangeBounds())
        addTransition(Fade(Fade.MODE_IN))
    }
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val callback = object : OnBackPressedCallback(enabled = false) {

            var controller: TransitionSeekController? = null

            @RequiresApi(34)
            override fun handleOnBackStarted(backEvent: BackEvent) {
                // Create the transition
                controller = TransitionManager.controlDelayedTransition(
                    binding.card,
                    transitionSet
                )
                changeTextVisibility(ShowText.SHORT)
            }

            @RequiresApi(34)
            override fun handleOnBackProgressed(backEvent: BackEvent) {
                // Play the transition as the user swipes back
                if (controller?.isReady == true) {
                    controller?.currentFraction = backEvent.progress
                }
            }

            override fun handleOnBackPressed() {
                // Finish playing the transition when the user commits back
                controller?.animateToEnd()
                this.isEnabled = false
            }

            @RequiresApi(34)
            override fun handleOnBackCancelled() {
                // If the user cancels the back gesture, reset the state
                transition(ShowText.LONG)
            }
        }

        binding.shortText.setOnClickListener {
            transition(ShowText.LONG)
            callback.isEnabled = true
        }

        this.requireActivity().onBackPressedDispatcher.addCallback(callback)
    }

    private fun transition(showText: ShowText) {
        TransitionManager.beginDelayedTransition(
            binding.card,
            transitionSet
        )
        changeTextVisibility(showText)
    }

    enum class ShowText { SHORT, LONG }
    private fun changeTextVisibility(showText: ShowText) {
        when (showText) {
            ShowText.SHORT -> {
                binding.shortText.isVisible = true
                binding.longText.isVisible = false
            }
            ShowText.LONG -> {
                binding.shortText.isVisible = false
                binding.longText.isVisible = true
            }
        }
    }
}
  
<?xml version="1.0" encoding="utf-8"?>
...
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ...>

        <TextView
            android:id="@+id/short_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            ... />

        <TextView
            android:id="@+id/long_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"
            .../>

    </androidx.constraintlayout.widget.ConstraintLayout>

予測型「戻る」遷移を使用する場合は、次の点に注意してください。

  • isSeekingSupported を使用して、遷移が予測型「戻る」をサポートしているかどうかを確認します。
  • カスタム遷移について true を返すように isSeekingSupported をオーバーライドします。
  • アニメーションごとに 1 つのコントローラを作成します。
  • 予測型「戻る」遷移は AndroidX 遷移でサポートされていますが、フレームワーク遷移ではサポートされていません。フレームワーク遷移から移行し、代わりに Animator と AndroidX 遷移を使用します。
  • 予測型「戻る」遷移は Android 14 以降を搭載したデバイスでサポートされており、下位互換性はありません。
  • XML シーンで作成された遷移もサポートされています。handleOnBackStarted で、TransitionSeekControllercontrolDelayedTransition の結果ではなく TransitionManager.createSeekController の結果に設定します。

Android 14 以降でカスタム アクティビティ遷移を追加する

Android 14 以降でカスタムのアクティビティ遷移で予測型「戻る」をサポートするには、overridePendingTransition ではなく overrideActivityTransition を使用します。つまり、ユーザーが後方にスワイプすると、遷移アニメーションが再生されます。

この仕組みを示す例として、アクティビティ B がバックスタック内のアクティビティ A の上に重ねられている場合を考えます。カスタム アクティビティ アニメーションは次のように処理します。

  • アクティビティ B の onCreate メソッド内で、開始遷移または終了遷移を呼び出します。
  • ユーザーがアクティビティ B に移動する場合は、OVERRIDE_TRANSITION_OPEN を使用します。ユーザーがスワイプしてアクティビティ A に戻る場合は、OVERRIDE_TRANSITION_CLOSE を使用します。
  • OVERRIDE_TRANSITION_CLOSE を指定した場合、enterAnim はアクティビティ A の開始アニメーション、exitAnim はアクティビティ B の終了アニメーションです。

フラグメントで予測型「戻る」のサポートを追加する

フラグメントで予測型「戻る」を実装する場合は、次の 2 つの方法があります。

既存の API を使用する

既存の API を使用することをおすすめします。これらの API を使用すると、画面の端からスワイプして、ジェスチャーで Animator または Androidx の遷移を操作できます。しきい値を超えてスワイプしたかどうかによって、操作が完了して前のフラグメントに戻るか、またはキャンセルされて現在のフラグメントに残るかが決まります。詳細については、アニメーションを使用してフラグメント間を移動するをご覧ください。

次の点に留意してください。

  • Transitions 1.5.0 以降と Fragment 1.7.0 以降をインポートします。Fragment 内の予測型「戻る」サポートの多くは、アニメーションをシークできる Transitions を使用しています(Transitions 1.5.0 以降でのみ可能)。
  • Fragment を FragmentManager または Navigation コンポーネントとともに使用して、バックスタックを処理します。バックスタックを独自で管理している場合、予測型「戻る」はサポートされません。FragmentManager が認識していないバックスタックから移行します。
  • 一部のライブラリには、予測型「戻る」のサポートが含まれています。ドキュメントをご確認ください。
  • Animator クラスと AndroidX Transition ライブラリがサポートされています。
  • Animation クラスとフレームワーク Transition ライブラリはサポートされていません。
  • 予測型アニメーションは、Android 14 以降を搭載したデバイスでのみ機能します。

予測型「戻る」のクロス フラグメントは、次のような状況で使用します。

マテリアル モーションの一部(MaterialFadeThroughMaterialSharedAxisMaterialFade など)は、1.12.02-alpha02 以降で予測型「戻る」をサポートしています。注: MaterialContainerTransform は予測型バックをサポートしていません。

コールバックを使用する

コールバックを使用してフラグメント間の遷移を作成できますが、コールバックを使用すると、ユーザーが後方にスワイプしたときに前のフラグメントが表示されないという既知の制限があります。予測型「戻る」の設計ガイダンスに対応するフラグメント間の共有要素遷移を作成するには、次の操作を行います。

OnBackPressedCallback を作成します。handleOnBackProgressed 内で、フラグメントをスケーリングしてシフトします。その後、バックスタックからポップします。次に、コールバックの外部で setSharedElementReturnTransition を使用して共有要素の遷移を実行します。

詳細については、GitHub のコードサンプルをご覧ください。

要件

次の表に、targetSdkVersioncompileSdkVersion、デバイスのバージョン、依存関係、マニフェスト フラグ、フラグメント フラグで制御される内容を示します。次の表はコード要件を示しています。

カテゴリ アニメーション compileSdk targetSdk デバイスのバージョン android:enableOnBackInvokedCallback 依存関係
システム アニメーション ホームに戻る 33 すべて 35 正しい なし
クロス アクティビティ 34 すべて 35 正しい なし
クロスタスク 34 すべて 35 正しい なし
プラットフォーム カスタムのクロス アクティビティ 34 すべて 35 正しい なし
Progress API プラットフォーム 34 すべて 34 正しい なし
マテリアル コンポーネント ボトムシート 34 すべて 34 正しい Material Component 1.10.0
サイドシート 34 すべて 34 正しい Material Component 1.10.0
ナビゲーション ドロワー 34 すべて 34 正しい Material Component 1.10.0
検索 34 すべて 34 正しい Material Component 1.10.0
Jetpack アニメーション カスタムの AndroidX のクロス フラグメント 34 すべて 34 正しい AndroidX Fragment 1.7
カスタムの AndroidX の遷移 34 すべて 34 正しい AndroidX Transition 1.5
Progress API Jetpack 34 すべて 34 正しい AndroidX Activity 1.8

参考情報