Android 使用 ScrollView 返回 Fragment 时共享元素转换

Android shared element transition on returning to Fragment with ScrollView

我有一个 GridView 包裹在一个 ScrollView 里面,我们称之为片段 A 和一些 CardViewsGridView 里面。我知道 GridViews 是可滚动的,但我将 GridView 的高度扩展到它的内容高度,因为我希望 GridView 内的元素和上面的布局一起滚动。我很清楚这不是使用 GridView 的正确方法,但我有自己的理由这样做,所以请忽略它。

无论如何,问题在于共享元素(CardView)转换在从片段 A 到片段 B 时效果很好,但在通过按下后退按钮或 [= 从片段 B 返回到片段 A 时效果不佳22=]

我以编程方式设置 CardViewstransitionName 值,并在我将其用于 Gridview 的适配器中为每个 CardView 设置唯一值并将其传递给在 CardViewonClick 方法上带有 bundle 参数的 Fragment B。然后在 Fragment B 的 onCreateView 方法中,我也将相同的值设置为其中的 CardView

这是我用来切换到片段 B 的代码:

Fragment fragment = new FragmentB()
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            // Defines enter transition only for shared element
            Transition changeBoundsTransition = TransitionInflater.from(mContext).inflateTransition(android.R.transition.move);
            fragment.setSharedElementEnterTransition(changeBoundsTransition);
            bundle.putString("transitionName", "card" + p.getId());
            fragment.setArguments(bundle);
            fragmentManager.beginTransaction()
                    .replace(R.id.main_container_wrapper, fragment)
                    .addToBackStack("package_root")
                    .addSharedElement(cv, "card" + p.getId())
                    .commit();

        }

这里是 FragmentB 的 onCreateView 方法:

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        String transitionName = getArguments().getString("transitionName");
        view.findViewById(R.id.cv_selected_package_card).setTransitionName(transitionName);
}

正如我上面所说,共享元素转换在转到 FragmentB 时效果很好,但从它返回时效果不佳。

我认为正在发生的事情是 FragmentA 在从 FragmentB 返回时重新加载,这就是为什么离开它和返回它时滚动状态不会保持不变的原因它从顶部显示。但是 Scroll 不是这里的主要问题,因为即使我 select 顶部的第一个 CardView 没有向下滚动,共享元素转换也无法在向后导航时工作。

目标 API 版本是 25,构建 API 版本是 25,我在虚拟设备 android API 级别 25.[=36 上测试应用程序=]

所以知道我该如何解决这个问题。

问题是我用来切换到下一个片段的 replace() 方法。这将破坏片段并将其从片段管理器中删除,并在需要时再次添加回来。因此,为了防止这种情况发生,我使用 add() 方法添加下一个片段,并使用 hide() 隐藏当前片段。

代码如下:

Fragment currentFragment = fragmentManager.findFragmentById(R.id.main_container_wrapper);
fragmentManager.beginTransaction()
               .hide(currentFragment)
                .add(R.id.main_container_wrapper, fragment)
                .addToBackStack(null)
                .addSharedElement(cv, "card" + p.getId())
                .commit();