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

JMR*_*ies 52 android android-viewpager android-transitions

我的应用程序包含一个视图,其中包含一个由少量片段组成的ViewPager.单击其中一个片段中的项目时,预期的行为是共享元素(在本例中为图像)转换为片段,该片段显示有关所单击内容的更多信息.

这是一个非常简单的视频,它应该是什么样子:

https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-114842.mp4

这只是使用片段 - >片段转换.

将起始片段放在ViewPager中时会出现问题.我怀疑这是因为ViewPager使用其父片段的子片段管理器,它与处理片段事务的活动的片段管理器不同.这是一个发生了什么的视频:

https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-120029.mp4

我非常肯定这里的问题,因为我上面解释的是子片段管理器与活动的片段管理器.以下是我进行转换的方式:

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();
Run Code Online (Sandbox Code Playgroud)

当两个片段都由活动的片段管理器管理时,这种方法很好,但是当我加载一个像这样的ViewPager时:

ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
pager.setAdapter(new Adapter(getChildFragmentManager()));
Run Code Online (Sandbox Code Playgroud)

ViewPager的子项不是由活动管理的,它不再起作用.

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

kha*_*kha 39

可能你已经找到了答案,但是如果你没有,这就是我在几个小时的挠头后做的修复.

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

  • FragmentsViewPager与延迟负载,这意味着活动返回比包含内部的其片段快得多ViewPager

  • 如果你像我一样,你ViewPager的孩子片段很可能是同一类型.这意味着,它们都共享相同的转换名称(如果您已在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);
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

现在有很多方法可以做到这一点,但这就是我在"细节"活动中最终得到的结果,即包含ViewPager(onCreate()但是你可以在任何地方真正做到)的活动:

_viewPager.setAdapter(_sectionsPagerAdapter);
_viewPager.setCurrentItem(position);
...
...
_pagerAdapter.getItem(position).setTransitionName(getResources().getString(R.string.transition_contenet_topic));
Run Code Online (Sandbox Code Playgroud)

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

实际的实现非常简单:

public void setTransitionName(String transitionName) {
    _transitionName = transitionName;
}
Run Code Online (Sandbox Code Playgroud)

然后在你的片段里面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);
}
Run Code Online (Sandbox Code Playgroud)

拼图的最后一部分是找出你的片段何时完全加载然后调用ActivityCompat.startPostponedEnterTransition(getActivity());.

在我的情况下,我的片段直到后来才完全加载,因为我从UI线程加载了大部分内容,这意味着我必须想办法在加载所有内容时调用它,但如果不是你的情况,你可以调用它你打电话后setTransitionNameLollipop().

这种方法的问题在于退出转换可能不起作用,除非您非常小心并exit在活动导航回之前重置"可见"片段上的转换名称.这可以很容易地完成:

  1. 听取您的页面更改 ViewPager
  2. 片段离开视图后立即删除转换名称
  3. 在可见片段上设置转换名称.
  4. 而不是打电话finish(),打电话ActivityCompat.finishAfterTransition(activity);

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

就我而言,我没有必要实施他的解决方案以及我发布的上述解决方案.

如果你有多个共享元素,我相信你可以弄清楚如何扩展方法以满足它们.