14

I use show/hide to display a fragment that takes up part of the screen. For some reason when the fragment is shown the slide_in_left animation plays, but when the fragment is being hidden there is no animation, the fragment just disappears. I've tried using the slide_in_left animation for both exit and enter, this did not help. When a trace the code into the support package, the animation does get created and the code for displaying it is being executed. (I traced the .hide call)

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

Just in case here's the xml for the slide_out_left animation

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

Edit: It's possible that the problem has something to do with the fact that my_fragment shares screen width with another fragment cotaining a webview. When .show is executed for my_fragment it becomes visible and shares space within a horizontal linear layout (how much screen width each of the two fragments takes up is determined by the weight parameter).

Leo K
  • 808
  • 1
  • 9
  • 24
  • For now, I bypassed this problem by showing the second fragment on top of the first one (paritally covering the first one). Under such a layout scenario animations work fine. – Leo K Dec 24 '12 at 13:42

5 Answers5

30

Try to use setCustomAnimations(int enter, int exit, int popEnter, int popExit) instead of setCustomAnimations(int enter, int exit) When you will call popupbackstack exit animation wont be called

Amlan
  • 520
  • 6
  • 10
4

Personally for me this is a bug with the zPosition for Fragment animations.

What you see is the new fragment "appearing" this is because the new fragment is attached underneath the current one.

So when trying to animate a fragment 'Over the top' of an existing fragment, it appears like nothing is happening then the new one just 'appears'.

I have tried many work arounds, playing with zPosition (only affects windows not layouts, so no effect to fragments), onAnimationCreate() bringing the root layout to front or even on animation start and stop... seems to do nothing.

So at this point in time without writing a complete custom animation for fragment transitions, they are a bit buggy at the moment.

You may have to play with. .add(Fragment) wait for it to be added, then call .remove(Fragment) removing the old fragment, that way the new fragment is physically placed on top of the existing fragment.

Chris.Jenkins
  • 13,051
  • 4
  • 60
  • 61
  • Sounds plausible, but it's not very clear why in a layout where one fragment is on top of the other the animations work fine. The code for displaying the Fragments stays the same so this zPosition problem should still be in effect? The workaround I mentioned turned out to be the preferred way, since the WebView fragment then does not need to re-render its contents. – Leo K Feb 20 '13 at 14:39
  • From further experience with animations I find more and more that these kinds of bugs are due to zPosition, so although my app no longer contains this exact functionality/bug I'm accepting your answer. – Leo K Mar 03 '14 at 10:23
  • Thanks @LeoK I am moving away from Fragments these days in favor of View+Controller pattern much like Squares Flow library. So much more flexible. – Chris.Jenkins Mar 03 '14 at 10:26
3

Try to use transitions instead. Here is the example from my project:

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

And also you can make your own transitions: https://medium.com/@belokon.roman/custom-transitions-in-android-f8949870bd63

2

I think it had the same situation that arises:

I have N fragments and I wanted to have a custom animation but I didn't want to reload the fragments, so doing an add and remove or a replace was not a solution, and with the show / hide I could not synchronize the animation between two fragments .

To fix it I had to use a FrameLayout for each fragment.

Here the code.

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

Then to control which fragment to display:

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

The key is in the bringToFront

I hope it has been helpfull!

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()
Ayush Sth
  • 317
  • 6
  • 11