片段共享元素转换不适用于 ViewPager [英] Fragment shared element transitions don't work with ViewPager

查看:17
本文介绍了片段共享元素转换不适用于 ViewPager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My app contains a view which consists of a ViewPager consisting of a handful of fragments. When you click on an item in one of these fragments, the expected behavior is for the shared element (in this case an image) to transition to the fragment which displays more information about the clicked content.

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

Here is a very simple video of what it should look like:

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

这只是使用 Fragment->Fragment 过渡.

This is just using a Fragment->Fragment transition.

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

The problem arises when you place the starting fragment inside a ViewPager. I suspect this is because the ViewPager uses its parent fragment's child fragment manager, which is different than the fragment manager of the activity, which is handling the fragment transaction. Here is a video of what happens:

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

正如我上面解释的那样,我很确定这里的问题是子片段管理器与活动的片段管理器.以下是我的过渡方式:

I'm pretty certain the issue here as I explained above is the child fragment manager vs the activity's fragment manager. Here is how I am making the transition:

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();

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

This works fine when both fragments are managed by the activity's fragment manager, but when I load up a ViewPager like this:

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

ViewPager 的子项不再由 Activity 管理,它不再工作.

The children of the ViewPager are not being managed by the activity, and it doesn't work anymore.

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

Is this an oversight by the Android team? Is there any way to pull this off? Thanks.

推荐答案

可能你已经找到了这个问题的答案,但如果你还没有,这就是我在摸索了几个小时后所做的修复它.

Probably you've already found an answer to this but in case you haven't, here's what I did to fix it after a few hours of scratching my head.

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

The problem I think is a combination of two factors:

  • ViewPager 中的 Fragments 加载延迟,这意味着活动返回的速度比 ViewPager<中包含的片段快得多/代码>

  • The Fragments in ViewPager load with a delay, meaning that the activity returns a lot faster than its fragments which are contained inside the ViewPager

如果你和我一样,你的 ViewPager 的子片段很可能是同一类型.这意味着,它们都共享相同的过渡名称(如果您已在 xml 布局中设置它们),除非您在代码中设置它们并且只在可见片段上设置一次.

If you are like me, your ViewPager's child fragments are most likely the same type. This means, they all share the same transition name (if you've set them in your xml layout), unless you set them in code and only set it once, on the visible fragment.

为了解决这两个问题,我这样做了:

To fix both of these problems, this is what I did:

1.修复延迟加载问题:

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

Inside your activity (the one that contains the ViewPager), add this line after super.onCreate() and before 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() 但你真的可以在任何地方做):

Now there are quite a few ways of going about doing this but this is what I ended up with inside my "detail" activity, i.e. the activity that contains the ViewPager (in the onCreate() but you can do it anywhere really):

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

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

You need to be careful since the Activity may not yet be attached to your ViewPager fragment so it's easier to just pass in the transition name from the activity to the fragment if you're loading it from a resource

实际的实现和你想象的一样简单:

The actual implementation is as simple as you expect:

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

然后在片段的 onViewCreated() 中,添加以下行:

Then inside your fragment's onViewCreated(), add this line:

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());.

The last piece of the puzzle is to find out when your fragment is fully loaded and then call ActivityCompat.startPostponedEnterTransition(getActivity());.

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

In my case, my fragments were not fully loaded until later since I'm loading most things off the UI thread which means I had to figure out a way to call this when everything was loaded but if that's not your case, you can call this right after you call setTransitionNameLollipop().

这种方法的问题是退出转换可能不起作用,除非您非常小心并在您退出活动以返回之前重置可见"片段上的转换名称.可以像这样轻松完成:

The problem with this approach is that the exit transition may not work unless you're very careful and reset the transition name on the "visible" fragment right before you exit the activity to navigate back. That can easily be done like so:

  1. 在您的 ViewPager
  2. 上收听页面变化
  3. 一旦您的片段不在视野范围内,请立即删除过渡名称
  4. 在可见片段上设置过渡名称.
  5. 不调用 finish(),而是调用 ActivityCompat.finishAfterTransition(activity);
  1. Listen to page change on your ViewPager
  2. Remove the transition name(s) as soon as your fragment is out of view
  3. Set the transition name(s) on the visible fragment.
  4. Instead of calling finish(), call ActivityCompat.finishAfterTransition(activity);

如果您返回转换需要转换到 RecyclerView 这是我的情况,这很快就会变得非常复杂.为此,@Alex Lockwood 在这里提供了一个更好的答案:ViewPager Fragments – Shared Element Transitions 这里有一个写得很好的示例代码(尽管比我刚刚写的要复杂得多):https://github.com/alexjlockwood/activity-transitions/tree/master/app/src/main/java/com/alexjlockwood/活动/过渡

This can get very complex very soon if you back transition needs to transition to a RecyclerView which was my case. For that, there's a much better answer provided by @Alex Lockwood here: ViewPager Fragments – Shared Element Transitions which has a very well written example code (albeit a lot more complicated than what I just wrote) here: https://github.com/alexjlockwood/activity-transitions/tree/master/app/src/main/java/com/alexjlockwood/activity/transitions

就我而言,我不必去实施他的解决方案,而我发布的上述解决方案适用于我的案例.

In my case, I didn't have to go so far as to implement his solution and the above solution that I posted worked for my case.

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

In case you have multiple shared elements, I'm sure you can figure out how to extend the methods in order to cater to them.

这篇关于片段共享元素转换不适用于 ViewPager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆