Fragment 同士の遷移時アニメーションで Predictive back を有効にする時の実装メモです。
これを書いている時点では、alpha 版のライブラリや Experimental な機能を使用しているため、将来的に変更される可能性があります。
実装
依存関係
ライブラリの依存は以下のバージョン以降である必要があります。
- Fragment 1.7.0 以降 or Transition 1.5.0 以降
- compileSdk 34
- material-components の Motion を使いたいならば 1.12.0 以降
Predictive back の有効
AndroidManifest で Predictive back を有効にします。
<!-- Application 全体で有効 -->
<application
...
android:enableOnBackInvokedCallback="true" />
<!-- or Activity 単位で有効 -->
<activity
...
android:enableOnBackInvokedCallback="true" />
次に Fragment で Predictive back を有効にします。
この有効は Application の onCreate
もしくは Activity の super.onCreate
の前に設定する必要があります。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
FragmentManager.enablePredictiveBack(true)
super.onCreate(savedInstanceState)
...
}
}
遷移アニメーションの実装
Jetpack の Navigation ではデフォルトでは遷移時のアニメーションが入っておらず、Predictive back を有効にしただけでは遷移時のアニメーションや連携は機能しません。
また、Fragment のスタックを独自で管理している場合も Predictive back は機能しないので、Jetpack の Navigation か FragmentManager を使っている必要があります。
パターン 1 : Navigation Component で遷移時アニメーションを設定する
Navigation Component で遷移時のアニメーションを設定するパターンです。
<navigation ...>
<fragment ...>
<action
...
app:enterAnim="@animator/nav_default_enter_anim"
app:exitAnim="@animator/nav_default_exit_anim"
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
</fragment>
</navigation>
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F126298%2F81c428fb-8a31-39c7-a0d1-f4d7695285f9.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=0f62a8cee90b661bad08776e5801ae3c)
パターン 2 : Transition でアニメーションを設定する
Transition で標準で用意されている AutoTransition
を設定して Fragment が表示するときのアニメーションを設定するパターンです。
AutoTransition
で適用されるアニメーション自体は Fade になっています。
class FragmentA: Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
exitTransition = AutoTransition()
reenterTransition = AutoTransition()
}
}
class FragmentB: Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = AutoTransition()
exitTransition = AutoTransition()
}
}
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F126298%2F4eb26a5a-1c67-55e2-805e-03e1b5e08b68.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=dc70366627c11a78f780b4723ad9e29e)
material-components の Motion にある Transition 系の API を使っている場合、Predictive back がサポートされているライブラリバージョンを使っているならば追加実装なしで機能します。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F126298%2F2e3fd103-0b1b-d884-338b-be328bc12c7c.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=b66c81f699d15bd45a3ecb2fb02c71ba)
パターン 3 : Shared element transition を設定する
Transition を使用する Shared element transition もパターン 2 同様に機能します。
ただし、設定できる Transition に制限があり、Transition の実装クラスで isSeekingSupported = true
であるものが Predictive back に対応しています。
また、Shared element trantision の Transition だけでなく、enterTransition
のような通常の Transition も設定する必要があります。
// In FragmentA
binding.card.setOnClickListener {
val extras = FragmentNavigatorExtras(
it to "shared_element_container",
binding.icon to "shared_element_icon"
)
findNavController().navigate(R.id.action_FragmentA_to_FragmentB, null, null, extras)
}
class FragmentB: Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = AutoTransition()
val transition = TransitionSet().apply {
addTransition(ChangeBounds())
addTransition(ChangeImageTransform())
}
sharedElementEnterTransition = transition
sharedElementReturnTransition = transition
}
}
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F126298%2F96b7145c-219f-f94e-05b7-067ddb36b234.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=c976b124294d735c1689c6fd4b36419d)