How to use shared element transitions in Navigatio

2020-02-08 04:53发布

I would like to add a shared elements transition using the navigation architecture components, when navigating to an other fragment. But I have no idea how. Also in the documentations there is nothing about it. Can someone help me?

9条回答
SAY GOODBYE
2楼-- · 2020-02-08 05:37

FirstFragment

val extras = FragmentNavigatorExtras(
    imageView to "secondTransitionName")
view.findNavController().navigate(R.id.confirmationAction,
    null, // Bundle of args
    null, // NavOptions
    extras)

first_fragment.xml

<ImageView
    android:id="@+id/imageView"
    android:transitionName="firstTransitionName"
    ...
 />

SecondFragment

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View {
    sharedElementEnterTransition = ChangeBounds().apply {
        duration = 750
    }
    sharedElementReturnTransition= ChangeBounds().apply {
        duration = 750
    }
    return inflater.inflate(R.layout.second_fragment, container, false)
}

second_fragment.xml

<ImageView
    android:transitionName="secondTransitionName"
    ...
 />

I tested it. It is worked.

查看更多
再贱就再见
3楼-- · 2020-02-08 05:37

Since 1.0.0-alpha06 the navigation component supports adding shared element transitions between destinations. Just add FragmentNavigatorExtras to navigate() call. More details: https://developer.android.com/guide/navigation/navigation-animate-transitions#shared-element

val extras = FragmentNavigatorExtras(
    imageView to "header_image",
    titleView to "header_title")
view.findNavController().navigate(R.id.confirmationAction,
    null, // Bundle of args
    null, // NavOptions
    extras)
查看更多
We Are One
4楼-- · 2020-02-08 05:38

So let's say that you have two Fragments, FragmentSecond and FragmentThird. Both have ImageView with the same transitionName, let's say : "imageView"

android:transitionName="imageView"

Just define a normal action between these fragments.

In FragmentSecond, let's add our extras

val extras = FragmentNavigatorExtras( binding.image to "imageView")

findNavController().navigate(R.id.action_secondFragment_to_thirdFragment , null, null , extras)

So we're saying that we want to share that ImageView, with that transitionName, with ThirdFragment

And then in ThirdFragment :

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Glide.with(this).load(IMAGE_URI).into(binding.headerImage)
    }

The only thing that we have to do is load the image in the two fragments from the same URL. The URL can be passed between fragments using a Bundle Object and pass it in the navigate call or as a destination argument in the navigation graph.

If you need it, i am preparing a sample about Navigation and there's SharedElementTransition too :

https://github.com/matteopasotti/navigation-sample

查看更多
可以哭但决不认输i
5楼-- · 2020-02-08 05:43

I took reference from this github sample https://github.com/serbelga/android_navigation_shared_elements

cardView.setOnClickListener{
  val extras = FragmentNavigatorExtras(
    imageView to "imageView"
  )
  findNavController().navigate(R.id.detailAction, null, null, extras)
}

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

It is working properly.

查看更多
家丑人穷心不美
6楼-- · 2020-02-08 05:43

To make this work from a recyclerView's ImageView the setup everything like the following:

val adapter = PostAdapter() { transitionView, post ->
    findNavController().navigate(
        R.id.action_postsFragment_to_postsDetailFragment,
        null,
        null,
        FragmentNavigatorExtras(transitionView to getString(R.string.transition_image)))
}

within the adapter this does the trick:

itemView.setOnClickListener {
    ViewCompat.setTransitionName(imageView, itemView.context.getString(R.string.transition_image))
    onClickedAction?.invoke(imageView, post)
}

You don't have to specify the transition name within the adapter's item's xml but simply set it from code as soon as the item gets clicked.

The onClickedAction looks like:

private val onClickedAction: ((transitionView: View, post: Post) -> Unit)?

and you pass it to your ViewHolder.

In the second Fragment you set the transition name to the ImageView in xml:

android:transitionName="@string/transition_image"

and assign the transition like

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val transition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
    sharedElementEnterTransition = transition
    sharedElementReturnTransition = transition
}
查看更多
Explosion°爆炸
7楼-- · 2020-02-08 05:48

I was finally able to get this to work: On Fragment B:

val transition = TransitionInflater.from(this.activity).inflateTransition(android.R.transition.move)

sharedElementEnterTransition = ChangeBounds().apply {
            enterTransition = transition
        }

Just make sure you have your transition names right in your views and you have NO entertTransition on Fragment B

查看更多
登录 后发表回答