Animate the transition between fragments
Asked Answered
S

9

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

Sinewy answered 8/2, 2011 at 11:29 Comment(1)
use ANIMATOR --- not Animation! use android.R.ANIMATOR.fade_in works, DON'T use android.R.ANIM.fade_in - it has behavior BUGSSerif
R
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.

Reconnoitre answered 8/2, 2011 at 17:22 Comment(17)
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?Soper
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...Dosage
@DaveMacLean added note on slides.Reconnoitre
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?Rosana
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).Whitefly
to perfrom top_to_bottom animation check here https://mcmap.net/q/101660/-fragment-standard-transition-not-animatingMornay
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.Imbrue
I've added NineOldAndroids support to the Google Support library. See github.com/kedzie/Support_v4_NineOldAndroids for details. It allows using Property Animations for Fragment Transitions, PageTransformers, and some other stuff.Scorbutic
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.Bergwall
@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?Giroux
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.Teece
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.Purse
@SohyunAhn you need to declare a getter and a setter 'setXFraction' and 'getXFraction' on a view you animateLogue
@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: mavyasoni9891.blogspot.com/2014/06/…Arette
@RomanNurik how to use setCustomAnimation while making the FragA animating below the FragB? I know that zAdjustment only works for windows animation! Any workaround?Nephrolith
@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 for this problem.Rainwater
Is there a way to get the (default, native) transition animation between Activities and set it to fragments? If so, how?Incomplete
A
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.

Arnaldo answered 30/11, 2015 at 6:25 Comment(13)
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)Bidden
Awesome solution. Similar approach and the same animation files work for transitions between activities.Dustidustie
What directory to you put the xml files? I put in Layout but it does not work, I am new to Android.Altricial
@MikeZriel, res -> anim -> put your xml hereArnaldo
Thanks Hiren, I change the speed (700) to (300) far better and more like iOSAltricial
Hmm, this works fine on the emulator but is crazy slow/laggy on my s6 edge device...June
Nvm, it was slow because I had the background image in the "drawable" folder and not in the "mipmap" folder :)June
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"Malcolm
Why this stuff gives me App Crash? I don't get any exception error message on android monitor.... why this happens only to me...Coextend
@MaggiePhillips, post your crash logArnaldo
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 xDCoextend
Animation is not working while creating Adapter classes. Any solution for this?Draft
does it still show the animation when u press the back key/go back to previous fragment?Jehoshaphat
U
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.

Unsteel answered 23/1, 2015 at 20:19 Comment(10)
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).Physicist
new Slide(...) : call requires API level 21Saloop
what getKey() stands for?Follower
@EranGoldin Nothing lasts forever.. would you scoff at an Android 2.0+ only solution today?Kriegspiel
@Kriegspiel 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.Physicist
So simple and great answer. but what is implementation of getKey() method?Hellfire
@Hellfire It's just a method that returns the fragment tag to identify it later. See: developer.android.com/reference/android/app/…, android.app.Fragment, java.lang.String)Unsteel
Works on API 16 like a charm by just using the support library.Irrepealable
OMG! I cant believe I haven't use this before, it looks like it works with some physics! Much obliged @Scorpiodawg!Shirlshirlee
This is the only one that I got working using androidx libraries. .setCustomAnimations does nothing.Amortization
R
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.

Rufina answered 7/3, 2013 at 18:30 Comment(0)
T
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.

Terzetto answered 29/10, 2014 at 9:8 Comment(4)
moving the view for 2000 px, is a very ugly solution.Dialogue
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)Austine
@MrPablo, the reason is probably that you haven't copy pasted the code above. setCustomAnimations should be called before the replace method.Consistent
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.Muscolo
Z
25

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

Zooid answered 12/2, 2017 at 22:14 Comment(0)
R
15

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

Reservist answered 27/2, 2018 at 9:35 Comment(1)
Woow.. this should be the accepted answer!! A simple and elegant solution. It's very smooth compared to the other suggests answersStovall
A
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()

Adz answered 20/4, 2013 at 3:17 Comment(0)
P
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.

Puissance answered 8/7, 2021 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.