What can I do to remap the animation to the right cell? All the cells got the same shared id.
In the first activity you should have some key that specifies the item that launches second activity. Let's assume you have a Map
of unique userId
s and User
s, i.e. Map<Integer, User>
.
- When you launch second activity pass this
User
's key in the map, let's say it is 42
. (In the map 42 -> John Doe
, and you are launching second activity for John Doe
).
setExitSharedElementCallback()
in the first activity and override onMapSharedElements()
.
override fun onMapSharedElements(names: MutableList<String>?,
sharedElements: MutableMap<String, View>?) {
// we will implement this in step 6
}
Override onActivityReenter()
in first activity and postpone transition with supportPostponeEnterTransition()
, in order not to show transition until we've made some actions (e.g. we want to scroll the list in order to show the item).
- In
onActivityReenter()
save the Bundle
that you've passed from second activity via Intent
(we'll see in step 7).
- After postponing transition in
onActivityReenter()
perform some changes to the UI based on the information you've added to this bundle. Particularly, in our case this bundle will include the original Integer
key of the User
that launched second activity. You may find current place of the User
in the list by this key, and scroll RecyclerView
to that new position. After making this item visible you can push the trigger and let the system start the transition by supportStartPostponedEnterTransition()
.
In SharedElementCallback::onMapSharedElements()
check weather the Bundle
that you have saved in the step 4 is null or not. If it is not null, that would mean that you have made something in second activity and you want remapping of shared elements to happen. This means you have to do something like this:
override fun onMapSharedElements(names: MutableList<String>?,
sharedElements: MutableMap<String, View>?) {
// `reenterBundle` is the `Bundle` you have saved in step 3
if (null != reenterBundle
&& reenterBundle!!.containsKey("KEY_FROM_ACTIVITY_2")
&& null != view) {
val key = reenterBundle!!.getInt("KEY_FROM_ACTIVITY_2");
val newSharedElement = ... // find corresponding view with the `key`
val newTransitionName = ... // transition name of the view
// clear previous mapping and add new one
names?.clear()
names?.add(newTransitionName)
sharedElements?.clear()
sharedElements?.put(newTransitionName, newSharedElement)
reenterBundle = null
} else {
// The activity is exiting
}
}
In second activity override finishAfterTransition()
:
override fun finishAfterTransition() {
val data = Intent()
data.putExtra("KEY_FROM_ACTIVITY_2", 42) // `42` is the original position that we passed to this activity via Intent when launching it
setResult(RESULT_OK, data)
super.finishAfterTransition()
}
In case that my user is no longer visible on the list, how can I replace the return animation with different animation?
You can either make it visible (e.g. by scrolling RecyclerView
so much, that your view becomes visible), or you can just remove shared elements transition in step 6 by clearing out names
and sharedElements
and not adding anything into them.
I hope you've learned the concept how it works although it seems a bit messy. But as a help for you I can share some code from an app written by me:
MainActivity - MainPresenter
DetailActivity