これは、android developer blogのContinuous Shared Element Transitions: RecyclerView to ViewPager 記事を解析した内容になります。

今回のサンプルは、RecyclerViewのGrid形式にして、アイテムをタップするとViewPager形式の
ViewにFadeOutしながら遷移するというもので、
ページビューで遷移元とは異なる画像に切り替えて、Grid画面に戻っても
SharedElementをかけています。

実装方法

まず、グリッド画面となるGridFragmentのonCreateViewで
sharedElementなどのアニメーションの設定をします。

prepareTranstion関数では、fragmentを遷移する時の遷移animationとcallbackの設定をしています。

遷移アニメーション方法はxmlで定義します。

続いて、GridFragmentからViewPagerに遷移する時とViewPagerからGridFragmentに遷移する際
に呼ばれるSharedElementCallbackクラスのセットと実装をします。

onMapSharedElements関数では、
RecyclerViewと対象のPageViewで表示されるImageの遷移先の設定をmapに埋め込んでいます。

また、ViewPagerが表示されるImagePageFragmentでも同じように遷移先を
SharedElementsにセットしています。

こう設定することで、ViewPagerで他のimageに切り替えた場合でも
ViewPagerで選択したimageをアニメーション対象にすることができます

遅延遷移をさせる

サンプルでは、urlから画像をloadする際など、
画像が読み込めていない場合のためにpostponeEnterTransition()
により、遅延遷移の設定をしています。

postponeEnterTransition() を読んだ場合に遷移をスタートさせるためには、
startPostponedEnterTransition()を呼びます。

表示されるGrid Imageの1つ1つはFragmentを継承したImageFragmentクラスになっています。

ImageFragmentクラスのonCreateViewでGlideを使って画像を読み込み
読み込みが終了したことを知らせるCallback関数onResouceReady()
または、読み込みが失敗した時に呼ばれるonLoadFailed()
startPostponedEnterTransition()を呼ぶことにより遅延遷移を実装しています。

sharedElementを使った遷移

RecyclerView.Adapterクラスを継承したGridAdapterクラス内にて、
clickListenerをセットしsharedElementを使った遷移をおこなっています。

まず、ViewPagerからバックキーを押して戻った際にsharedElementを用いた遷移を
行えるように、Activityの位置を保存するためのstatic変数に位置を代入します。

続いて、アニメーションの対象元から自身を除くために、excludeTarget()を呼びます。

最後にFragmentを切り替える際にaddSharedElement()を呼び、sharedElementの設定をし、
commit()を実行します。

addSharedFragment

sharedElement View: A View in a disappearing Fragment to match with a View in an appearing Fragment.
name String: The transitionName for a View in an appearing Fragment to match to the shared element.

遷移対象となるnameは、onBind関数で設定しています。

PageViewから戻った際にスクロールポジションを合わせる

GridFragmentのonCreatedViewにて、LayoutChangeListenerをセットし、
Activityに保存していたポジションに戻すことでスクロール位置をPageViewで
選択されたイメージの位置に移動させています。

以上になります。

全体のsourceはdeveloper pageのgitを参照ください。
clone先
https://github.com/google/android-transition-examples.git

Pocket