303

I'm trying to animate the transition between fragments. I got the answer from the following
Android Fragments and animation

FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);

DetailsFragment newFragment = DetailsFragment.newInstance();

ft.replace(R.id.details_fragment_container, newFragment, "detailFragment");

// Start the animated transition.
ft.commit();

And my R.anim.slide_in_left

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromXDelta="50%p" android:toXDelta="0"
            android:duration="@android:integer/config_mediumAnimTime"/>
       <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>

But when I tried this it showed

02-08 16:27:37.961: ERROR/AndroidRuntime(1717): FATAL EXCEPTION: main
02-08 16:27:37.961: ERROR/AndroidRuntime(1717): java.lang.RuntimeException: Unknown animator name: translate
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:129)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:126)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:93)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.loadAnimator(AnimatorInflater.java:72)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.loadAnimator(FragmentManager.java:621)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:733)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.BackStackRecord.run(BackStackRecord.java:578)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1217)

Any ideas? When I checked Honeycomb API reference translate is there. What did I miss?
Is there any other way to animate the transition between fragments? Thank you

Community
  • 1
  • 1
Labeeb Panampullan
  • 34,521
  • 28
  • 94
  • 112
  • use ANIMATOR --- not Animation! use android.R.ANIMATOR.fade_in works, DON'T use android.R.ANIM.fade_in - it has behavior BUGS – StepanM Mar 02 '18 at 10:07

9 Answers9

360

You need to use the new android.animation framework (object animators) with FragmentTransaction.setCustomAnimations as well as FragmentTransaction.setTransition.

Here's an example on using setCustomAnimations from ApiDemos' FragmentHideShow.java:

ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);

and here's the relevant animator XML from res/animator/fade_in.xml:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_quad"
    android:valueFrom="0"
    android:valueTo="1"
    android:propertyName="alpha"
    android:duration="@android:integer/config_mediumAnimTime" />

Note that you can combine multiple animators using <set>, just as you could with the older animation framework.


EDIT: Since folks are asking about slide-in/slide-out, I'll comment on that here.

Slide-in and slide-out

You can of course animate the translationX, translationY, x, and y properties, but generally slides involve animating content to and from off-screen. As far as I know there aren't any transition properties that use relative values. However, this doesn't prevent you from writing them yourself. Remember that property animations simply require getter and setter methods on the objects you're animating (in this case views), so you can just create your own getXFraction and setXFraction methods on your view subclass, like this:

public class MyFrameLayout extends FrameLayout {
    ...
    public float getXFraction() {
        return getX() / getWidth(); // TODO: guard divide-by-zero
    }

    public void setXFraction(float xFraction) {
        // TODO: cache width
        final int width = getWidth();
        setX((width > 0) ? (xFraction * width) : -9999);
    }
    ...
}

Now you can animate the 'xFraction' property, like this:

res/animator/slide_in.xml:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:valueFrom="-1.0"
    android:valueTo="0"
    android:propertyName="xFraction"
    android:duration="@android:integer/config_mediumAnimTime" />

Note that if the object you're animating in isn't the same width as its parent, things won't look quite right, so you may need to tweak your property implementation to suit your use case.

onexf
  • 3,674
  • 3
  • 22
  • 36
Roman Nurik
  • 29,665
  • 7
  • 84
  • 82
  • 8
    I got the fade_in and fade_out to work, but the others in /res/animator give errors. And none of those even appear to be for sliding in and sliding out. I've tried to write my own xml's to do this, but all I end up with is fragments on top of fragments. Some more help please? – Dave MacLean Feb 26 '11 at 01:16
  • And what about the translation ? How do you do a translation with values in percentage in a objectAnimator define in XML, please ? I didn't succeed in animate AdapterViewFlipper during flipping with vertical slide animations define in xml... – GBouerat Dec 06 '11 at 08:49
  • @DaveMacLean added note on slides. – Roman Nurik Dec 07 '11 at 19:58
  • 6
    I'm getting 11-19 10:27:50.912: W/PropertyValuesHolder(23107): Method setXFraction() with type float not found on target class class android.widget.FrameLayout. But in my XML I have my custom view MyFrameLayout. Any ideas? – barkside Nov 19 '12 at 10:28
  • Using the new Animation framework only permits targetting ~30% of the devices out there, which, on commercial products, probably isn't acceptable. Yes, I realise there NineOldAndroids exists, but Google aren't providing their own support. Much like their design reliance on the ActionBar (with the only usable implementation provided by Jake Wharton). – James Nov 26 '12 at 12:00
  • to perfrom top_to_bottom animation check here http://stackoverflow.com/a/13582907/336990 – CoDe Nov 27 '12 at 11:15
  • 13
    Actually, Roman, the advice should go the other way too: When using the Support Library, you need to use the old animation framework (android.R.anim) with FragmentTransaction.setCustomAnimations a.o. – pjv Dec 22 '12 at 16:29
  • I've added NineOldAndroids support to the Google Support library. See http://www.github.com/kedzie/Support_v4_NineOldAndroids for details. It allows using Property Animations for Fragment Transitions, PageTransformers, and some other stuff. – mark.kedzierski May 27 '13 at 03:30
  • It should also be noted that an implementation like this doesn't account for padding in the parent view. If the container that the fragments are animated within has padding, that presets the "x" property of the fragment view and has to be account for as the final "x" position of the animation destination...it can't just be zero all the time. – devunwired Jul 05 '13 at 15:33
  • @RomanNurik How would you suggest doing this with FragmentTransaction (non-support library). Would you have to return one of these custom views with `getXFraction()` in `OnCreateView()` in your fragment? – vinc3m1 Aug 20 '13 at 22:46
  • I don't know why it happened, but I found that "xFraction" property name is not working. Instead of "xFraction", setting property name as "x" is working. – Sohyun Ahn May 12 '14 at 06:27
  • Just to add for the case of setting CustomAnimation on fragmentTransaction for 3.0+, you need to extend the parent Layout of your Fragment's view. For instance, if your fragment's root Layout is a RelativeLayout, you'll require to extend RelativeLayout and add getter setter for xFraction or any other property you want. Then it will apply to the fragment. – Achin Kumar May 20 '14 at 19:34
  • @SohyunAhn you need to declare a getter and a setter 'setXFraction' and 'getXFraction' on a view you animate – Boy Jul 31 '14 at 13:27
  • 1
    @RomanNurik this answer worked great on most devices, but for some users (specifically on some Samsung Galaxy S3/4 phones) the width wasn't getting reported during the animations for some reason, causing the fragment to never appear. I was able to get it working for those users using an OnPredrawListener as shown here: http://mavyasoni9891.blogspot.com/2014/06/fragment-transaction-above-android-40.html – ajpolt Oct 07 '14 at 14:43
  • @RomanNurik how to use `setCustomAnimation` while making the FragA animating below the FragB? I know that zAdjustment only works for windows animation! Any workaround? – Muhammad Babar May 20 '15 at 10:25
  • @RomanNurik `setXFraction` should delay the execution until the layout is finished. On some devices (e.g. Xperia with activated STAMINA) the Fragment will not show up at all, because the animations are disabled. [Here is my solution](http://stackoverflow.com/a/41473673/321106) for this problem. – artkoenig Jan 04 '17 at 21:44
  • Is there a way to get the (default, native) transition animation between Activities and set it to fragments? If so, how? – android developer May 04 '20 at 10:47
207

I have done this way:

Add this method to replace fragments with Animations:

public void replaceFragmentWithAnimation(android.support.v4.app.Fragment fragment, String tag){
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
    transaction.replace(R.id.fragment_container, fragment);
    transaction.addToBackStack(tag);
    transaction.commit();
}

You have to add four animations in anim folder which is associate with resource:

enter_from_left.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="-100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

exit_to_right.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

enter_from_right.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

exit_to_left.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="-100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

Output:

enter image description here

Its Done.

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
  • 18
    Great solution. However I am unsure why you swapped the directions to RTL. My method: `.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)` – zed May 17 '16 at 09:31
  • 2
    Awesome solution. Similar approach and the same animation files work for transitions between activities. – Stan Jul 20 '16 at 08:15
  • What directory to you put the xml files? I put in Layout but it does not work, I am new to Android. – Mike Zriel Aug 04 '16 at 12:47
  • 1
    @MikeZriel, res -> anim -> put your xml here – Hiren Patel Aug 04 '16 at 12:49
  • 5
    Thanks Hiren, I change the speed (700) to (300) far better and more like iOS – Mike Zriel Aug 04 '16 at 13:18
  • Hmm, this works fine on the emulator but is crazy slow/laggy on my s6 edge device... – Christer Oct 18 '16 at 13:05
  • Nvm, it was slow because I had the background image in the "drawable" folder and not in the "mipmap" folder :) – Christer Oct 18 '16 at 13:32
  • 1
    Uhm. `setCustomAnimations()` expects resources of type `animator`, not `anim`. Attempting to use the above code as-is results in a runtime error: "Unknown animator name: translate" – Nathan Osman Mar 21 '17 at 18:56
  • Why this stuff gives me App Crash? I don't get any exception error message on android monitor.... why this happens only to me... – KoreanXcodeWorker Aug 13 '17 at 09:41
  • @MaggiePhillips, post your crash log – Hiren Patel Aug 13 '17 at 09:46
  • 3
    LOL, i came back with solution. I was importing android.app.fragment and FragmentManager on each java class. After checking some materials, I've found that using 'setCustomAnimations()' needs android.support.v4 library to be imported. important to say that should be 'support.v4.app' ! I replaced all the methods 'getFragmentManager()' with 'getSupportFragmentManager()', and all the import 'android.app.Fragment/FragmentManager...' to 'android.support.v4.app....', then this animation started to work well without crash... If you guys are stuck in similar cases, read my solution. Thx Hiren Patel xD – KoreanXcodeWorker Aug 13 '17 at 11:17
  • 1
    Animation is not working while creating Adapter classes. Any solution for this? – Nik Mar 13 '18 at 11:49
  • does it still show the animation when u press the back key/go back to previous fragment? – Jono Jul 29 '18 at 10:05
67

If you can afford to tie yourself to just Lollipop and later, this seems to do the trick:

import android.transition.Slide;
import android.util.Log;
import android.view.Gravity;
.
.
.
f = new MyFragment();
f.setEnterTransition(new Slide(Gravity.END));
f.setExitTransition(new Slide(Gravity.START));
getFragmentManager()
    .beginTransaction()
    .replace(R.id.content, f, FRAG_TAG)  // FRAG_TAG is the tag for your fragment
    .commit();

Kotlin version:

f = MyFragment().apply {
    enterTransition = Slide(Gravity.END)
    exitTransition = Slide(Gravity.START)
}
fragmentManager
    .beginTransaction()
    .replace(R.id.content, f, FRAG_TAG)  // FRAG_TAG is the tag for your fragment
    .commit();

Hope this helps.

Birju Vachhani
  • 6,072
  • 4
  • 21
  • 43
scorpiodawg
  • 5,612
  • 3
  • 42
  • 62
  • 1
    While that will achieve it on Lollipop, it's hardly practical as the percentage of device running Lollipop is negligible (currently 1.6% of Android devices are running Lollipop). – Eran Goldin Feb 27 '15 at 17:59
  • 1
    `new Slide(...)` : call requires API level 21 – Chintan Soni Dec 21 '15 at 07:27
  • what getKey() stands for? – Alvaro Mar 05 '16 at 13:42
  • 16
    @EranGoldin Nothing lasts forever.. would you scoff at an Android 2.0+ only solution today? – Tom Oct 27 '16 at 01:41
  • @Tom you have a point. However when your app has a large user base ou can't just bump the API level. If most of your users won't be able to run your app anymore after, that is no solution at all. – Eran Goldin Oct 30 '16 at 00:13
  • So simple and great answer. but what is implementation of getKey() method? – Chirag Dec 26 '17 at 07:31
  • @Chirag It's just a method that returns the fragment tag to identify it later. See: https://developer.android.com/reference/android/app/FragmentTransaction.html#replace(int, android.app.Fragment, java.lang.String) – scorpiodawg Dec 29 '17 at 00:23
  • 1
    Works on API 16 like a charm by just using the support library. – fdermishin Mar 21 '18 at 22:07
  • 1
    OMG! I cant believe I haven't use this before, it looks like it works with some physics! Much obliged @Scorpiodawg! – ZooMagic Jun 28 '18 at 14:06
  • This is the only one that I got working using androidx libraries. `.setCustomAnimations` does nothing. – The Berga Mar 10 '20 at 11:26
46

Nurik's answer was very helpful, but I couldn't get it to work until I found this. In short, if you're using the compatibility library (eg SupportFragmentManager instead of FragmentManager), the syntax of the XML animation files will be different.

Community
  • 1
  • 1
strangeluck
  • 846
  • 9
  • 10
28

Here's a slide in/out animation between fragments:

FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.animator.enter_anim, R.animator.exit_anim);
transaction.replace(R.id.listFragment, new YourFragment());
transaction.commit();

We are using an objectAnimator.

Here are the two xml files in the animator subfolder.

enter_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
     <objectAnimator
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:duration="1000"
         android:propertyName="x"
         android:valueFrom="2000"
         android:valueTo="0"
         android:valueType="floatType" />
</set>

exit_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
    <objectAnimator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:propertyName="x"
        android:valueFrom="0"
        android:valueTo="-2000"
        android:valueType="floatType" />
</set>

I hope that would help someone.

kirilv
  • 1,373
  • 1
  • 18
  • 24
  • 39
    moving the view for 2000 px, is a very ugly solution. – carlo.marinangeli Feb 20 '15 at 01:12
  • 4
    The exit_anim just "pops" off screen for me, it doesn't animate back across the screen. Any ideas? I am using `.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)` – Mr Pablo Dec 09 '15 at 13:29
  • @MrPablo, the reason is probably that you haven't copy pasted the code above. setCustomAnimations should be called before the replace method. – Galya Aug 12 '16 at 06:41
  • In This case, If I replace other fragment with animation and I do minimize the app immediately before animation time-out or duration over and again come back to the application, it will display previous fragment and current fragment parallel. – Prince Dholakiya Dec 04 '18 at 05:18
25

For anyone else who gets caught, ensure setCustomAnimations is called before the call to replace/add when building the transaction.

Charlie
  • 2,876
  • 19
  • 26
14

Try using this simple and fasted solution. Android provides some default animations.

fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
fragmentManager.addOnBackStackChangedListener(this);
fragmentTransaction.replace(R.id.frame, firstFragment, "h");
fragmentTransaction.addToBackStack("h");
fragmentTransaction.commit();

Output:

enter image description here

Gowthaman M
  • 8,057
  • 8
  • 35
  • 54
12

Android SDK implementation of FragmentTransaction wants an Animator while support library wants an Animation, don't ask me why but after strangeluk's comment I looked into android 4.0.3 code and support library. Android SDK uses loadAnimator() and support library uses loadAnimation()

sherpya
  • 4,890
  • 2
  • 34
  • 50
0

In an effort to add a more modern answer to this old question, if you've moved to Material Design, this can easily be done using the provided motion library--more details at https://material.io/develop/android/theming/motion.

Bink
  • 1,934
  • 1
  • 25
  • 41