ViewPager碎片 - 共享元素转换

28
我正在开发的应用程序显示一个图像网格。当您点击一张图片时,它会进入详情视图。详情视图包含一个ViewPager,允许您在网格中的每个图像之间滑动。这是通过传递路径列表(包含网格中的每个图像)以及被点击的图像的偏移量来完成的,以便ViewPager可以设置为最初显示该页面。
在ViewPager的当前偏移页的片段中如何进行共享元素转换?网格(RecyclerView)图像应该扩展到当前页的全屏图像。我看到了推迟和恢复活动转换的能力,所以应用程序将等待从磁盘加载图像后再显示共享元素转换。但是我想要能够使它动画到视图页面的正确页面,并在用户返回时退出到当前页面(因为您可以在页面之间滑动)。如果您现在切换到另一页,则初始页面就是动画返回到网格中的位置。
目前,我在ViewPager的片段中为每个图像分配一个过渡名称,格式为“image_[index]”。当我启动详细信息活动时,我使用相同的过渡名称,索引是偏移量。
与此相关的是,我还想知道如何使涟漪效果在长时间按下时起作用。当您更改视图的激活状态时,涟漪似乎会取消。我想要类似Gmail的效果,在长时间按下完成并触发激活状态后,涟漪会重新开始并迅速结束。

你可能想在另一篇帖子中提出有关ripple的第二个问题。此外,当我有更多时间时,我可以给出有关view pager和共享元素的更深入的答案,但现在你可以查看这个示例项目。我几周前写了它,听起来它几乎完全符合你所描述的。 :P - Alex Lockwood
@AlexLockwood 说得好。哇,你说得对,我刚刚运行了它,它几乎就是我需要的;我将在接下来的几天里仔细研究它,谢谢! - afollestad
你好,这对我不起作用。我的尝试是在ViewPager的片段中有一个列表,在单击任何项时,我想将图像传输到其详细信息片段。我尝试了这里得到的每个可能的解决方案,但什么都没有起作用。任何帮助将不胜感激。提前致谢。 - Harry Sharma
2个回答

35
据我所知(如果我有错,请纠正),您想要实现的基本上是这样的:假设您有一个MainActivity、一个DetailsActivity和一组任意的图像。 MainActivity在网格中显示图像集,而DetailsActivity在水平的ViewPager中显示相同的图像集。当用户在MainActivity中选择一张图片时,该图片应从其在网格中的位置转换到第二个活动的ViewPager中的正确页面。
我们要解决的问题是“如果用户在DetailsActivity内切换页面会怎么样?”如果发生这种情况,我们希望更改将在返回过渡期间使用的共享图像。默认情况下,活动转换框架将使用在进入转换期间使用的共享元素...但是视图页已更改,因此我们显然希望以某种方式覆盖此行为。为此,我们需要在您的MainActivityDetailsActivityonCreate()方法中设置一个SharedElementCallback并覆盖onMapSharedElements()方法,如下所示:
private final SharedElementCallback mCallback = new SharedElementCallback() {
    @Override
    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
        if (mCurrentImagePosition != mOriginalImagePosition) {
            View sharedView = getImageAtPosition(mCurrentImagePosition);
            names.clear();
            sharedElements.clear();
            names.add(sharedView.getTransitionName());
            sharedElements.put(sharedView.getTransitionName(), sharedView);
        }
    }

    /**
     * Returns the image of interest to be used as the entering/returning
     * shared element during the activity transition.
     */
    private View getImageAtPosition(int position) {
        // ...
    }
};

为了获得更完整的解决方案,我创建了一个GitHub上的示例项目,可以实现这个效果(代码太多无法在单个StackOverflow答案中发布)。


你好,这对我不起作用。我的尝试是在ViewPager的片段中有一个列表,在单击任何项时,我想将图像传输到其详细信息片段。我尝试了这里得到的每个可能的解决方案,但什么都没有起作用。任何帮助将不胜感激。提前致谢。 - Harry Sharma
谢谢,非常有用! - schwertfisch
你好,我的演示与你在Github上的非常相似,唯一的区别是第二个Activity中的ViewPager中有一个ImageView,我只想将图像共享到第一个ImageView。我的问题是当我进入第二个Activity时,第一个ImageView无法加载图像,如果我取消共享元素动画,它会加载。@Alex Lockwood - zys

4
我假设您正在使用Fragment Transitions,而不是在Activities之间进行动画。虽然在Activity Transitions和Fragment Transitions中都可以做到,但是具体的代码有些不同。然而,在Fragment Transitions中并没有可用的延迟函数。
addSharedElement需要一个第二个参数。如果您在调用它时知道目标Fragment中的特定名称,则可以选择在详细信息Fragment中使用该名称。如果您不知道,则可以选择任何名称,并使用设置在Fragment上的SharedElementCallback进行重映射。
fragment.setEnterSharedElementCallback(new SharedElementCallback() {
    @Override
    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
        sharedElements.put("detailView", mTargetDetailView);
    }
});

如果在返回的过程中不匹配,则再次调用remap。这可能会在调用片段和被调用片段中都出现 - 在调用片段中,您使用setExitSharedElementCallback。我预计这也是您的应用程序的情况。
同样,在Activity转换中,您设置相同的SharedElementCallback并使用相同的映射,但是您是在Activity上设置它。

这绝对是我想做的进展,问题在于有两个活动。一个显示包含图像网格的片段。另一个包含一个ViewPager,其中包含详细信息片段。 - afollestad
您正在使用Activity转换,并且恰好您的视图在片段中。您可能需要推迟进入转换或在onCreate中执行待处理的片段事务。您现在遇到了什么问题? - George Mount

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接