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

这是一个非常简单的视频,内容如下:

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

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

当您将起始片段放在ViewPager中时,就会出现问题。我怀疑这是因为ViewPager使用其父片段的子片段管理器,该子片段管理器与处理片段事务的 Activity 的片段管理器不同。以下是发生的情况的视频:

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

我可以肯定的是,如上所述,这里的问题是子片段管理器与 Activity 的片段管理器。这是我进行过渡的方式:

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

当两个片段都由 Activity 的片段管理器管理时,这很好用,但是当我像这样加载ViewPager时:
ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
pager.setAdapter(new Adapter(getChildFragmentManager()));

ViewPager的子级不由该 Activity 管理,并且不再起作用。

这是Android团队的疏忽吗?有什么办法可以做到这一点?谢谢。

最佳答案

可能您已经找到了解决方法,但是如果您没有找到答案,这是我挠头几个小时后要解决的方法。

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

  • 延迟加载Fragments中的ViewPager,这意味着 Activity 返回的速度比ViewPager中包含的片段
  • 快得多
  • 如果您和我一样,则ViewPager的子片段很可能是同一类型。这意味着,它们都共享相同的过渡名称(如果您已在xml布局中设置它们),除非您在可见的片段上将其设置为仅在代码中设置且仅设置一次。

  • 为了解决这两个问题,这是我所做的:

    1.解决延迟加载问题:

    在您的 Activity 中(包含ViewPager的 Activity ),在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.修复具有相同过渡名称的多个片段的问题:

    现在有很多方法可以做到这一点,但这就是我在“详细” Activity (即包含ViewPager的 Activity (在onCreate()中,但是您可以在任何地方实际使用))中最终得到的结果:
    _viewPager.setAdapter(_sectionsPagerAdapter);
    _viewPager.setCurrentItem(position);
    ...
    ...
    _pagerAdapter.getItem(position).setTransitionName(getResources().getString(R.string.transition_contenet_topic));
    

    您需要注意,因为Activity可能尚未附加到ViewPager片段上,因此,如果从资源中加载从 Activity 到片段的过渡名称,则更容易

    实际的实现与您期望的一样简单:
    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()之后。

    这种方法的问题在于,除非您非常小心并在对 Activity 进行exit导航之前将其重置为“可见”片段上的过渡名称,否则退出过渡可能无法工作。可以很容易地像这样完成:
  • 收听ViewPager上的页面更改
  • 一旦您的片段不在 View 中,请删除过渡名称
  • 在可见片段上设置过渡名称。
  • 而不是finish(),而是调用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/activity/transitions

    就我而言,我不必去实现他的解决方案,而我发布的上述解决方案对我的案例也很奏效。

    如果您有多个共享元素,我相信您可以弄清楚如何扩展方法以迎合它们。

    10-07 19:46
    查看更多