如何使用片段回退栈和共享元素转场?

3
共享元素转换替换了片段,因此我无法将其添加到后退堆栈并在按下后退箭头按钮时调用popbackstack。 我有一个主活动,里面有一个主要片段,主要片段处理一个表格布局,因此每个选项卡都是一个带有内部可滚动视图的片段。当单击可滚动视图元素时,共享元素转换开始到显示元素详细信息的新片段。
这是适配器,在其中单击元素:
holder.image.setTransitionName("transition" + holder.getAdapterPosition());
if (fragment instanceof tab1_anime) {
     ((tab1_anime) fragment).openShowElementFragment(holder.getAdapterPosition(), v.findViewById(R.id.main_image));
}

这是我的选项卡片段中的openShowElementFragment:
public void openShowElementFragment(int position, View view) {
        AddElement element = anime_list.get(position);
        ShowElementFragment showElementFragment = new ShowElementFragment();
        Bundle bundle = new Bundle();
        bundle.putString("transitionName", "transition" + position);
        bundle.putSerializable("element", element);
        bundle.putInt("position", position);
        bundle.putInt("from", 0);
        showElementFragment.setArguments(bundle);
        ((MainActivity) context).showFragmentWithTransition(this, showElementFragment, "showElementFragment", view, "transition" + position);
    }

这是前面代码块中调用的openshowelementfragment函数:
public void showFragmentWithTransition(Fragment current, Fragment newFragment, String tag, View sharedView, String sharedElementName) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        // check if the fragment is in back stack
        boolean fragmentPopped = fragmentManager.popBackStackImmediate(tag, 0);
        if (fragmentPopped) {

        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                current.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                current.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));

                newFragment.setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
            }
            fragmentManager.beginTransaction()
                    .replace(R.id.fragmentHolder, newFragment)
                    .addToBackStack(null)
                    .addSharedElement(sharedView, sharedElementName)
                    .commit();
        }
    }

这是返回箭头按钮:

back_arrow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getSupportFragmentManager().popBackStack();
            }
        });

如果我尝试添加新的片段而不是替换旧的片段,则根本没有动画。
如果我尝试用新的片段替换旧的片段,并仍然使用添加到返回堆栈(null),则共享元素转换从开始到结束都有效,但最终的片段没有数据,为空:

enter image description here

我也尝试了:

getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.fragmentHolder,  new MainFragment())
                .addToBackStack(null)
                .commit();

但是这样退出时共享元素转换不起作用:

enter image description here


你有没有阅读关于在使用RecyclerView时返回共享元素转换的文档 - ianhanniballake
@ianhanniballake 是的,但如果我理解正确,那个案例是从片段到回收站视图,而不是我的情况。 - shybaka
这正是你的返回转换。 - ianhanniballake
2个回答

0

你所谓的sharedElementName实际上是一个transitionName

a) 参考示例并没有直接操作后退栈:
Android Fragment Transitions: RecyclerView to ViewPager & Blog

b) 手动事务可能需要按照不同的方法调用顺序:

getSupportFragmentManager().beginTransaction()
    .addSharedElement(sharedElement, transitionName)
    .replace(R.id.container, newFragment)
    .addToBackStack(null)
    .commit();

另请参阅示例,了解如何设置备用转换,与以下内容进行比较:

TransitionInflater.from(this).inflateTransition(R.transition.default_transition)

无论 R.transition.default_transition 是什么。

当使用相同的转换方式而不是进入/退出转换方式时,它可能看起来很奇怪,就像 NavAction 一样。FragmentNavigator.Extras 可以用于在使用导航组件时应用进入/退出转换,这也可以与 ActionBar 结合使用。选项 a) 可能较为简单。b) 类似于 this Kotlin 示例可能更有意义。 当支持进入/退出转换时,构建笨重的导航 FX 是毫无意义的 out-of-the-box。也许在加载图像时考虑使用 Glide


假设有以下的build.gradle文件;没有必要重新发明轮子。
dependencies {
    androidTestImplementation "androidx.navigation:navigation-testing:2.5.3"
    implementation 'androidx.navigation:navigation-runtime:2.5.3'
    implementation 'androidx.navigation:navigation-fragment:2.5.3'
    implementation 'androidx.navigation:navigation-ui:2.5.3'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2' 
    implementation 'com.github.bumptech.glide:glide:4.14.2' 
}

那么使用 FragmentNavigator.ExtrasNavigation 可能是当前的方法:

Bundle navArgs = new Bundle();
navArgs.putInt("position", position);

FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
    .addSharedElement(sharedElement, transitionName)
    .build();

Navigation.findNavController(view).navigate(
    R.id.details, // ID of Nav destination
    navArgs,      // Bundle of args
    null,         // NavOptions
    extras);

我们也可以在XML的<action/>节点中定义transitionName。


*"FX"是什么?是指Fragment transition*吗?还是其他什么? - undefined

0

我认为你的问题与退出过渡有关,因为你得到了空列表的解决方案,现在,为了检查退出过渡效果,请查看以下代码。

 public void showFragmentWithTransition(Fragment current, Fragment newFragment, String tag, View sharedView, String sharedElementName) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        // check if the fragment is in back stack
        boolean fragmentPopped = fragmentManager.popBackStackImmediate(tag, 0);
        if (fragmentPopped) {

        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                current.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                current.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));

                newFragment.setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
            }
             getSupportFragmentManager().beginTransaction()
                 .addSharedElement(sharedElement, transitionName)
                 .replace(R.id.container, newFragment)
                 .addToBackStack(null)
                 .commit();
        }
    }

在这里,我添加了两行新的代码来实现退出过渡效果。

            newFragment.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
            newFragment.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
如果它不起作用,那么请按照下面的链接操作,我认为它会对你有所帮助。 https://medium.com/@bherbst/fragment-transitions-with-shared-elements-7c7d71d31cbb

1
使用相同的转换两次没有意义...通常是两个转换,而一个可以分配四个不同的转换。 - Martin Zeitler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接