SharedElementTransition with Navigation Architecture Component

이 기사는?

  • RecyclerView(일람 화면) -> 세부 화면 구성
  • SharedElementTransition 적용
  • Navigation Architecture Component에서 Fragment->Fragment 마이그레이션

  • 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()
  • 공유하려는 뷰를 위한 고유 설정TransitionName
  • RecyclerView 내의 프로젝트라면position 등을 이용하여 유일하게
  • 상세 화면으로 전달TransitionName
  • 마이그레이션 처리addSharedElement
  • 상세 화면

  • sharedElementEnterTransition
  • 이전 화면과 공유된 ViewTransitionName
  • 에 전달 설정

    실시


    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하면, 만약, 만약...
    Activity->Activity 시 이동하지만 Fragment->Fragment는 동작하지 않음
    무슨 제한이 있습니까?
    이동만 하면 돼요.
    디테일에서 되돌릴 때 애니메이션이 없습니다
    RecyclerView 그리기 전에 android.R.transition.move 를 실행하여 문제를 해결합니다.
    이것도 Activity->Activity 때 설정이 없어도 움직이는데 Fragment 간의 이동이라면 여러 가지 마음대로 달라질까요?

    좋은 웹페이지 즐겨찾기