【问题标题】:Fragment shared element transitions don't work with ViewPager片段共享元素转换不适用于 ViewPager
【发布时间】:2015-08-18 03:52:57
【问题描述】:

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

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

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

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

将起始片段放在 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();

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

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

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

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

【问题讨论】:

  • 您能否提供您的活动、父片段和子片段的完整代码?谢谢:)
  • 我遇到了嵌套Fragments 和共享元素转换的问题,here 是我的问题。
  • 为什么将 ChildFragmentManager 而不是 FragmentManger 传递给适配器?
  • @EE66 我相信 ChildFragmentManager 被传递是因为 ViewPager 子项不是由 Activity 而是由 ViewPager 管理的,所以它不是同一个片段管理器。
  • 您好,这对我不起作用..我正在尝试的是,我在 viewpager 的片段中有一个列表,点击任何我想将图像处理到其详细片段的项目..我尝试了我在这里找到的所有可能的解决方案..但没有任何效果..任何帮助将不胜感激。提前致谢。

标签: android android-viewpager android-transitions


【解决方案1】:

您可能已经找到了答案,但万一您还没有找到,我在摸索了几个小时后,采取了以下措施来解决这个问题。

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

  • ViewPager 中的 Fragments 加载有延迟,这意味着活动返回的速度比包含在 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);
    ...
}

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 – Shared Element Transitions 这里有一个写得很好的示例代码(尽管比我刚刚写的要复杂得多):https://github.com/alexjlockwood/activity-transitions/tree/master/app/src/main/java/com/alexjlockwood/activity/transitions

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

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

【讨论】:

  • 您好,这对我不起作用..我正在尝试的是,我在 viewpager 的片段中有一个列表,点击任何我想将图像处理到其详细片段的项目..我尝试了我在这里找到的所有可能的解决方案..但没有任何效果..任何帮助将不胜感激。提前致谢。
  • 如何通过片段事务实现这一点可以在这里找到:stackoverflow.com/a/26984314/2380518
  • @ligi 很高兴听到它对您有所帮助。
  • 我遇到了一个问题。在 ViewPager 中,我滚动到下一个项目,然后在 BackPressed 上它不会动画到上一个也有 ViewPager 的 Activity 上的新项目。它返回到旧的选定项目。
  • @kha cay 你帮我解决这个问题stackoverflow.com/q/59431465/4291272
【解决方案2】:

关于活动 supportPostponeEnterTransition();

当你的片段被加载时(尝试同步它们,可能使用 EventBus 或其他)

startPostponedEnterTransition();

参考此示例

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

【讨论】:

    【解决方案3】:

    我最近一直在用这个把头撞到墙上。我想要的只是 ViewPager 中的 Fragment 以启动另一个具有良好扩展卡类型共享元素过渡的 Fragment。上面的建议都不适合我,所以我决定尝试启动一个类似对话框的 Activity:

    <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>
    

    然后从 Fragment 启动 Activity:

    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() 第二个参数相同)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-22
      • 2021-06-29
      • 1970-01-01
      相关资源
      最近更新 更多