4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SharedElementTransition with Navigation Architecture Component

Last updated at Posted at 2019-05-06

この記事は?

  • RecyclerView(一覧画面) -> 詳細画面 の構成
  • SharedElementTransition の適用
  • Fragment -> Fragment 遷移をNavigation Architecture Componentで行う

output.gif

利用SDK

project/build.gradle
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0-alpha02"
app/build.gradle
apply plugin: 'androidx.navigation.safeargs.kotlin'

// 省略

implementation "androidx.navigation:navigation-fragment-ktx:2.1.0-alpha02"

手順まとめ

一覧画面

  • postponeEnterTransition()を実行しておく
  • RecyclerViewの描画直前に、startPostponedEnterTransition()を実行
  • 共有したいViewに一意のTransitionNameを設定
    • RecyclerView内のアイテムなら、position等を利用して一意にする
  • 詳細画面にTransitionNameを渡す
  • 遷移処理時に、addSharedElementをする

詳細画面

  • sharedElementEnterTransitionを設定する
  • 前画面と共有するViewに渡されてきたTransitionNameを設定する

実装

Navigation Graph

xmlを記載したら、一度ビルドしましょう。
後ほど必要なクラスが生成されます。

nav_graph
<?xml version="1.0" encoding="utf-8"?>
<navigation
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/home_fragment"
    >

    <!-- 省略 -->
 
   <!-- 一覧画面 -->
    <fragment
        android:id="@+id/todo_list_fragment"
        android:name="com.helmos.mysandbox.presentation.todo.TodoListFragment"
        android:label="TodoListFragment"
        tools:layout="@layout/fragment_todo_list"
        >
        <action
            android:id="@+id/start_detail"
            app:destination="@id/todo_detail_fragment"
            >
            <argument
                android:name="todo"
                app:argType="com.helmos.mysandbox.data.entity.Todo"
                />
            <argument
                android:name="transition_name"
                app:argType="string"
                />
        </action>
    </fragment>

    <!-- 詳細画面 -->
    <fragment
        android:id="@+id/todo_detail_fragment"
        android:name="com.helmos.mysandbox.presentation.todo.detail.TodoDetailFragment"
        android:label="TodoDetailFragment"
        tools:layout="@layout/fragment_todo_detail"
        >
        <argument
            android:name="todo"
            app:argType="com.helmos.mysandbox.data.entity.Todo"
            />
        <argument
            android:name="transition_name"
            app:argType="string"
            />
    </fragment>
</navigation>

一覧画面

RecyclerViewの使い方などは省略しています。

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

    // 省略

    // RecyclerViewのTransitionは遅延させる
    postponeEnterTransition()
    todoRecycler.viewTreeObserver.addOnPreDrawListener {
        startPostponedEnterTransition()
        true
    }
}

// onBindViewHolder 共有要素にTransitionNameを設定
view.transitionName = "todo_transition_$position"

// 一覧アイテムクリック時の処理
setOnItemClickListener { item, view ->
    val todo = (item as TodoItem).todo
    val sharedView = view.findViewById<View>(R.id.todo_icon)
    // 画面遷移
    findNavController().navigate(
            // 自動生成されるDirectionsクラス
            TodoListFragmentDirections.startDetail(todo, sharedView.transitionName),
            // addSharedElementを行ってくれるUtilクラス
            FragmentNavigatorExtras(
                    sharedView to sharedView.transitionName
            )
    )
}

詳細画面

TodoDetailFragment

// 自動生成される引数データクラス
private val args by navArgs<TodoDetailFragmentArgs>()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
}

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

    // 省略

    // 共有要素に設定
    todoImage.transitionName = args.transitionName

}

迷った点/今後調べること

android.R.transition.moveを使わないとダメだった

自作のtransitionだと、
Activity->Activity時には動いていたが、Fragment->Fragmentでは動作しなかった
何か制約があるのかも?

移動させるだけであれば、android.R.transition.moveでOK

詳細から戻った時にアニメーションしなかった

RecyclerView描画直前にstartPostponedEnterTransition()を実行して解決
こちらもActivity->Activity時には設定していなくても動いていたので、Fragment間の遷移だと色々と勝手が違いそう??

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?