Activity transition when data changes

2019-07-23 16:52发布

I got images adapter where each item is user image, when clicked it opens a new activity with selected user image, so I mark the image as shared element and using activity transitions.

Part of the actions that I perform on the second activity effects all of the users, so the adapter calls notifyDataSetChanged and reset the position to the top of the list.

When this happens it mess up the return animation, when I close the second activity and return to the list the data in it been changed so the image get animated to the wrong cell.

I got two questions:

  1. What can I do to remap the animation to the right cell? All the cells got the same shared id...
  2. In case that my user is no longer visible on the list, how can I replace the return animation with different animation?

1条回答
欢心
2楼-- · 2019-07-23 17:28

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 userIds and Users, i.e. Map<Integer, User>.

  1. 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).
  2. 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                            
    }
    
  3. 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).

  4. In onActivityReenter() save the Bundle that you've passed from second activity via Intent (we'll see in step 7).
  5. 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().
  6. 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
        }                            
    }
    
  7. 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

查看更多
登录 后发表回答