[Android]Navigation/Fragmentでの共通要素遷移(Shared element transition)の実装

Google Developer Blogの記事 共通要素を使った途切れない画面遷移: RecyclerView から ViewPager へ で紹介されているようなページ間で共通の要素が使いまわされる遷移を実装してみました。
読書の記録アプリで初挑戦し以下のようになりました。

この記事では実装時に困ったことの以下の点の備忘録です。

  1. Navigationコンポーネントを使ったときの設定
  2. Navigationで指定したページ間遷移が実行されない
  3. excludeTargetを指定しても移動する要素が残る

共通要素を使った画面遷移方法は以下のような分かりやすい記事があるのでそちらを参照ください。

Navigate between fragments using animations
SharedElementTransition with Navigation Architecture Component
[Android]Shared Element Transition を試してみる

1.Navigationコンポーネントを使ったときの設定

 1.遷移元Fragment内の共通要素のプロパティ(transitionName)に文字列をセットする

// 共通要遷移処理
viewSource.transitionName = "shareView"

2.遷移先Fragment内の共通要素のプロパティ(transitionName)に1.で設定した文字列をonCreateViewハンドラでセットする

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    destinationView.transitionName = "shareView"

    return binding.root
}

3.遷移先FragmentのonCreateハンドラでsharedElementEnterTransitionをセットする

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
}

4.navigate実行時に共通要素のViewと1.でセットした文字列のMAPを渡す。

        findNavController().navigate(
            action,
            // 共通要遷移処理
            FragmentNavigatorExtras(
                sharedView to sharedView.transitionName
            )
        )

2.Navigationで指定したページ間遷移アニメーションが実行されない

sharedElementEnterTransitionをセットするとNavigationの定義ファイル(nav_graph.xml)設定したページ遷移のアニメーションが実行されませんでした。このような場合は、遷移元/遷移先でexitTransition/reenterTransitionを指定することで遷移アニメーションを実行できます。

例)遷移元Fragment

//navigateを呼ぶ前にアニメーションをセットする
//次ページへ遷移するときのアニメーション
val fadeout = Fade()
fadeout.mode = Visibility.MODE_OUT
fadeout.excludeTarget(sharedView, true)
exitTransition = fadeout

//次ページから戻るときのアニメーション
val fadein = Fade()
fadein.mode = Visibility.MODE_IN
fadein.excludeTarget(sharedView, true)
reenterTransition = fadein

例)遷移先Fragment

//表示されるときのアニメーションをセット。onCreateViewで呼ぶ
val fade = Fade()
fade.mode = Visibility.MODE_IN
enterTransition = fade

//前のページに戻るときのアニメーションをセット。バックボタンが押されたときにセットする
val fade = Fade()
fade.mode = Visibility.MODE_OUT
fade.excludeTarget(R.id.image_icon, true)
returnTransition = fade

3.excludeTargetを指定しても移動する要素が残る

Navigate between fragments using animationsでは共通要素遷移時に動かす要素をページ遷移のアニメーションから除外するためexcludeTargetを使い除外するに書かれています。
この除外処理を正しく行うためには遷移アニメーションのViewをしている必要があります。

val fadeout = Fade()
fadeout.mode = Visibility.MODE_OUT
//遷移アニメーションの対象をFragment内のViewに指定する
fadeout.addTarget(getView())
//共通要素のViewを遷移アニメーションの対象外とする
fadeout.excludeTarget(sharedView, true)

0 件のコメント :

コメントを投稿