片段共享元素转换不适用于ViewPager

我的应用程序包含一个由几个片段组成的ViewPager组成的视图。 当您单击其中一个片段中的某个项目时,预期的行为是针对共享元素(在本例中为图片)转换到显示有关点击内容的更多信息的片段。

这是一个非常简单的video:

这只是使用片段 – >片段过渡。

将起始片段放置在ViewPager中时会出现问题。 我怀疑这是因为ViewPager使用它的父级片段的子片段pipe理器,它不同于正在处理片段事务的活动的片段pipe理器。 这是一个发生了什么事的video:

我非常确定这个问题,因为我上面解释的是孩子片段pipe理器与活动的片段pipe理器。 以下是我正在进行转变:

SimpleFragment fragment = new SimpleFragment(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.am_list_pane, fragment, fragment.getClass().getSimpleName()); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { TransitionSet enterTransition = new TransitionSet(); enterTransition.addTransition(new ChangeBounds()); enterTransition.addTransition(new ChangeClipBounds()); enterTransition.addTransition(new ChangeImageTransform()); enterTransition.addTransition(new ChangeTransform()); TransitionSet returnTransition = new TransitionSet(); returnTransition.addTransition(new ChangeBounds()); returnTransition.addTransition(new ChangeClipBounds()); returnTransition.addTransition(new ChangeImageTransform()); returnTransition.addTransition(new ChangeTransform()); fragment.setSharedElementEnterTransition(enterTransition); fragment.setSharedElementReturnTransition(returnTransition); transaction.addSharedElement(iv, iv.getTransitionName()); } transaction.addToBackStack(fragment.getClass().getName()); transaction.commit(); 

这两个片段由活动的片段pipe理器pipe理时,这工作正常,但是当我加载一个ViewPager是这样的:

 ViewPager pager = (ViewPager) view.findViewById(R.id.pager); pager.setAdapter(new Adapter(getChildFragmentManager())); 

ViewPager的孩子没有被这个活动pipe理,而且也不能工作了。

这是Android团队的疏忽吗? 有什么办法可以解决这个问题吗? 谢谢。

也许你已经find了一个答案,但如果你没有,这是我做了几个小时后,我的头修理它。

我认为这个问题是两个因素的综合:

  • Fragmnets中的ViewPager加载延迟,这意味着该活动的返回速度比ViewPager中包含的片段快

  • 如果你像我一样,你的ViewPager的子片段很可能是同一types的。 这意味着,它们都共享相同的转换名称(如果您已将它们设置在xml布局中), 除非您在代码中设置它们,并只在可见片段中设置一次

要解决这两个问题,这是我做的:

1.解决延迟加载问题:

在您的活动(包含ViewPager )中,在super.onCreate()setContentView()之前添加此行:

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityCompat.postponeEnterTransition(this); // This is the line you need to add setContentView(R.layout.feeds_content_list_activity); ... } 

2.修复具有相同转换名称的多个片段的问题:

现在有很多方法可以做到这一点,但是这就是我在“细节”活动中的结果,即包含ViewPager的活动(在onCreate()但是您可以在任何地方做到这一点):

 _viewPager.setAdapter(_sectionsPagerAdapter); _viewPager.setCurrentItem(position); ... ... _pagerAdapter.getItem(position).setTransitionName(getResources().getString(R.string.transition_contenet_topic)); 

您需要小心,因为Activity可能尚未附加到ViewPager片段,因此如果从资源加载它,将活动的转换名称传递到片段更容易

实际执行过程如您所期望的那样简单:

 public void setTransitionName(String transitionName) { _transitionName = transitionName; } 

然后在你的片段的onViewCreated() ,添加这一行:

 public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ... if (_transitionName != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { setTransitionNameLollipop(); } ... } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void setTransitionNamesLollipop() { _imgTopic.setTransitionName(_transitionName); } 

最后一块难题是找出你的片段何时被完全加载,然后调用ActivityCompat.startPostponedEnterTransition(getActivity());

在我的情况下,我的碎片没有完全加载,直到后来我从UI线程加载大部分的东西,这意味着我必须找出一种方式来调用这个时,一切都加载,但如果这不是你的情况,你可以调用这个你调用setTransitionNameLollipop()

这种方法的问题是,退出过渡可能无法正常工作,除非您非常小心,并在exit活动之前重新设置“可见”片段上的过渡名称以回溯。 这可以很容易地做到这一点:

  1. 听你的ViewPager上的页面更改
  2. 片段不在视图中时,立即删除过渡名称
  3. 在可见片段上设置过渡名称。
  4. 而不是调用finish() ,调用ActivityCompat.finishAfterTransition(activity);

如果你需要过渡到一个RecyclerView ,那么这很快会变得非常复杂。 为此,@Alex Lockwood在这里提供了一个更好的答案: ViewPager Fragments – 共享元素转换 ,它有一个写得很好的示例代码(尽pipe比我刚刚写的更复杂): https : //github.com / alexjlockwood /活动的转变/树/主/应用程序/ SRC /主/ JAVA / COM / alexjlockwood /活动/过渡

就我而言,我不必为了实现他的解决scheme而走得太远了,而我贴出的上述解决scheme为我的案例工作。

如果你有多个共享元素,我相信你可以找出如何扩展这些方法来迎合他们。

在活动supportPostponeEnterTransition();

当你的片段被加载(尝试同步它们,也许与事件总线或其他)

startPostponedEnterTransition();

参考这个例子

http://www.androiddesignpatterns.com/2015/03/activity-postponed-shared-element-transitions-part3b.html

最近我一直用头撞墙。 我只想要一个ViewPager中的片段来启动另一个带有扩展卡片types共享元素转换的片段。 上面的build议没有为我工作,所以我决定尝试启动类似于对话框的活动:

 <style name="AppTheme.CustomDialog" parent="MyTheme"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:backgroundDimEnabled">true</item> </style> 

然后从片段启动活动:

 Intent intent = new Intent(getContext(), MyDialogActivity.class); ActivityOptionsCompat options = ActivityOptionsCompat .makeSceneTransitionAnimation(getActivity(), Pair.create(sharedView, "target_transition")); ActivityCompat.startActivity(getActivity(), intent, options.toBundle()); 

在Fragment布局中,在sharedView上放置一个android:transition_name,在Activity布局中放置android:transition_name =“target_transition”(与Pair.create()第二个参数相同)。