Activity 数据变化时的转换

Activity transition when data changes

我得到了图像适配器,其中每个项目都是用户图像,单击它会打开一个新的 activity 和选定的用户图像,所以我将图像标记为共享元素并使用 activity 转换。

我在第二个 activity 上执行的部分操作会影响所有用户,因此适配器调用 notifyDataSetChanged 并将位置重置为列表顶部。

发生这种情况时,它会弄乱 return 动画,当我将第二个 activity 和 return 关闭到列表中时,其中的数据已更改,因此图像动画化为单元格错误。

我有两个问题:

  1. 如何将动画重新映射到正确的单元格?所有单元格都有相同的共享 ID...
  2. 如果我的用户不再出现在列表中,我该如何用不同的动画替换 return 动画?

What can I do to remap the animation to the right cell? All the cells got the same shared id.

在第一个 activity 中,您应该有一些键来指定第二个 activity 启动的项目。假设您有 Map 个独特的 userIdUser,即 Map<Integer, User>.

  1. 当您启动第二个 activity 时,在地图中传递这个 User 的键,假设它是 42。 (在地图 42 -> John Doe 中,您正在为 John Doe 发射第二个 activity。
  2. setExitSharedElementCallback() 在第一个 activity 中覆盖 onMapSharedElements().

    override fun onMapSharedElements(names: MutableList<String>?,
                                 sharedElements: MutableMap<String, View>?) {
        // we will implement this in step 6                            
    }
    
  3. 覆盖 onActivityReenter() in first activity and postpone transition with supportPostponeEnterTransition(),以便在我们执行某些操作之前不显示转换(例如,我们想要滚动列表以显示项目)。

  4. onActivityReenter()中保存你从第二个activity通过Intent传递的Bundle(我们将在第7步中看到)。
  5. onActivityReenter() 中推迟过渡后,根据您添加到此捆绑包中的信息对 UI 进行一些更改。特别是,在我们的例子中,这个包将包含 User 的原始 Integer 密钥,它启动了第二个 activity。您可以通过此键找到 User 在列表中的当前位置,然后滚动 RecyclerView 到该新位置。使此项目可见后,您可以按下触发器并让系统通过 supportStartPostponedEnterTransition().
  6. 开始转换
  7. SharedElementCallback::onMapSharedElements()中检查你在第4步中保存的Bundle是否为空。如果它不为空,则意味着您在秒 activity 中做了一些事情并且您希望重新映射共享元素。这意味着你必须做这样的事情:

    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
        }                            
    }
    
  8. 秒activity覆盖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?

您可以使其可见(例如,通过滚动 RecyclerView 太多,您的视图变得可见),或者您可以通过清除 namessharedElements 并且不向其中添加任何内容。

我希望你已经了解了它的工作原理,尽管它看起来有点混乱。但作为对您的帮助,我可以分享我编写的应用程序中的一些代码:

MainActivity - MainPresenter

DetailActivity