退出动画无法工作;FragmentTransaction自定义动画在隐藏时无法工作

14

我使用show/hide来显示占据屏幕一部分的片段。但奇怪的是,当片段显示时,slide_in_left动画会播放,但当片段被隐藏时,没有动画,片段只是消失了。我尝试将slide_in_left动画用于exit和enter,但这没有帮助。当我跟踪代码到支持包中时,动画确实被创建并且执行了显示它的代码。(我跟踪了.hide调用)

FragmentManager fm = _activity.getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.my_fragment);
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_left);
if (fragment.isHidden()) {
    ft.show(fragment);
    fragment.setUserVisibleHint(true);
} else {
    ft.hide(fragment);
}
ft.commit();
< p> 如果需要,这是 slide_out_left 动画的 XML 代码。 < /p>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="-50%p"
        android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
        android:duration="@android:integer/config_mediumAnimTime" />
</set>

编辑: 问题可能与my_fragment与包含Web视图的另一个片段共享屏幕宽度有关。当执行.show命令时,my_fragment变为可见,并在水平线性布局中共享空间(两个片段占用多少屏幕宽度由权重参数确定)。


目前,我通过在第一个片段的上方显示第二个片段(部分覆盖第一个片段)来绕过这个问题。在这种布局情况下,动画效果良好。 - Leo K
5个回答

30

尝试使用setCustomAnimations(int enter, int exit, int popEnter, int popExit)代替setCustomAnimations(int enter, int exit),当您调用popupbackstack时,退出动画将不会被调用。


1
这与弹出后退堆栈时的动画无关。他在询问退出和进入片段动画的分层。 - Jason Hu
非常感谢。这应该是被接受的答案。 - Rahul Bansal
非常感谢。是的,这应该是被接受的答案。正如所说,当您调用popupbackstack退出动画时不会被调用。 - Sahana Prabhakar
非常感谢您,您救了我的命。 - bluesway

4

对我个人来说,这是与片段动画的zPosition有关的错误。

你看到的是新的片段“出现”,这是因为新的片段附加在当前片段下面。

因此,在尝试将片段“覆盖”到现有片段上时,似乎什么也没有发生,然后新的片段只是“出现”。

我尝试了许多解决方法, 调整zPosition(仅影响窗口而不是布局,对片段没有影响),onAnimationCreate() 将根布局置于前台或甚至在动画开始和结束时...似乎没有任何作用。

所以,在这个时间点上,除非编写完整的自定义片段转换动画,否则它们现在有点瑕疵。

您可能需要尝试使用 .add(Fragment) 等待它被添加,然后调用 .remove(Fragment) 删除旧片段,这样新片段就被实际放置在现有片段的上方。


听起来很有道理,但不是很清楚为什么在一个片段位于另一个片段上方的布局中,动画可以正常工作。显示片段的代码保持不变,因此这个zPosition问题应该仍然存在?我提到的解决方法最终成为首选方式,因为WebView片段不需要重新渲染其内容。 - Leo K
通过进一步的动画经验,我发现这些错误往往是由于zPosition引起的,因此尽管我的应用程序不再包含这个确切的功能/错误,但我接受了你的答案。 - Leo K
感谢@LeoK,我现在更倾向于使用视图+控制器模式,而不是Fragment,就像Square的Flow库一样。这种方式更加灵活。 - Chris.Jenkins

3

尝试使用过渡效果。这是我项目中的一个例子:

private fun changeFragment(fragment: BaseFragment, addBackStack: Boolean) {
    // Set transitions
    fragment.enterTransition = Fade(Fade.IN).apply { duration = 800 }
    fragment.exitTransition = Slide(Gravity.TOP).apply { duration = 800 }
    // Your transaction below
    val fragmentTransaction = supportFragmentManager.beginTransaction()

    fragmentTransaction.replace(R.id.fragmentContainer, fragment)
    if (addBackStack) {
        fragmentTransaction.addToBackStack(fragment.javaClass.name)
    }
    fragmentTransaction.commit()
}

同时,您也可以自己制作过渡效果:https://medium.com/@belokon.roman/custom-transitions-in-android-f8949870bd63


2
  supportFragmentManager.beginTransaction()
     .setCustomAnimations(R.anim.enter_slide_up, R.anim.exit_slide_down,R.anim.enter_slide_up, R.anim.exit_slide_down)
     .add(R.id.nav_host_fragment, fragment)
        .addToBackStack(BACK_STACK)
        .commit()

2

我认为出现了相同的情况:

我有N个片段,我想要自定义动画,但我不想重新加载片段,所以使用add和remove或replace不是一个解决方案,而使用show/hide无法在两个片段之间同步动画。

为了解决这个问题,我必须为每个片段使用FrameLayout。

以下是代码。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_above="@+id/main_bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/library"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <FrameLayout
            android:id="@+id/search"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <FrameLayout
            android:id="@+id/discover"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </FrameLayout>

    <com.roughike.bottombar.BottomBar
        android:id="@+id/main_bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        app:bb_tabXmlResource="@xml/main_bb_tabs"
        app:bb_inActiveTabColor="@color/taupegray"
        app:bb_activeTabColor="@color/green_apple"
        app:bb_showShadow="true"/>

</RelativeLayout>

然后控制显示哪个片段:
private void showFragment(BaseFragment fragment) {
    Animation animation = AnimationUtils.loadAnimation(this,
                R.anim.slide_in_from_right);

    if (fragment instanceof DiscoverFragment) {
        mDiscoverContainer.bringToFront();
        mDiscoverContainer.startAnimation(animation);

        return;
    }

    if (fragment instanceof LibraryFragment) {
        mLibraryContainer.bringToFront();
        mLibraryContainer.startAnimation(animation);

        return;
    }

    if (fragment instanceof SearchFragment) {
        mSearchContainer.bringToFront();
        mSearchContainer.startAnimation(AnimationUtils.loadAnimation(animation);

        return;
    }
}

关键在于bringToFront

希望这对您有所帮助!


bringToFront 方法在哪里? - Francis Bacon
该方法已经在所有视图中实现,您只需要调用它即可。 - Julián Falcionelli

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