Android Fragments and animation
Asked Answered
E

6

277

How should you implement the sort of sliding that for example the Honeycomb Gmail client uses?

Can TransactionManager handle this automatically by adding and removing the Fragments, it's kind of difficult to test this due to the emulator being a slideshow :)

Enrollment answered 27/1, 2011 at 14:55 Comment(0)
R
395

To animate the transition between fragments, or to animate the process of showing or hiding a fragment you use the Fragment Manager to create a Fragment Transaction.

Within each Fragment Transaction you can specify in and out animations that will be used for show and hide respectively (or both when replace is used).

The following code shows how you would replace a fragment by sliding out one fragment and sliding the other one in it's place.

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

To achieve the same thing with hiding or showing a fragment you'd simply call ft.show or ft.hide, passing in the Fragment you wish to show or hide respectively.

For reference, the XML animation definitions would use the objectAnimator tag. An example of slide_in_left might look something like this:

<?xml version="1.0" encoding="utf-8"?>
<set>
  <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="x" 
    android:valueType="floatType"
    android:valueFrom="-1280"
    android:valueTo="0" 
    android:duration="500"/>
</set>
Riotous answered 27/1, 2011 at 17:24 Comment(18)
When i tried this it show RuntimeException: Unknown animator name: translate.Benzofuran
Make sure the animations defined in slide_in_left and right are constructed using a set of objectAnimator definitions rather than the old animation definition.Riotous
@Dave: Added an example to the answer.Riotous
That helped a lot. I was on the right track but just didn't get all the way there. For the other readers, you could also have android:interpolator as an attribute, with your favorite one specified (such as "@android:interpolator/linear"). It defaults to "@android:interpolator/accelerate_decelerate".Lessee
This does not work with compatability api. Application will crash while trying to inflate objectAnimator on devices with api level < 11.Elbowroom
what if one wants to apply a custom animation ? the way you apply for other views using startAnimation methodLucullus
What if I want to translate from 0% to 100%? This was supported by the translate object, but I can't used the "old" animations with FragmentTransaction. Also if I use the objectAnimator, will it stil work when running on devices lower than API 11?Systematic
I'm targeting API Level 7 with the compatability APIs. Is there a way for me to animate Fragments?Corpulent
@JarrodSmith you can try using a compatibility library like NineOldAndroids to bring the Honeycomb API down to Eclair.Shoshanashoshanna
If you want to make a transition that works on both 2.x and 3.0+ you should first look here: https://mcmap.net/q/101660/-fragment-standard-transition-not-animating.Akkerman
I can't get animation to start when I hide(). Works only on showSubmissive
@LabeebP, this only works when using the support library. See the following answer for more info: https://mcmap.net/q/101662/-swap-fragment-in-an-activity-via-animationCerated
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.Mcabee
ObjectAnimator causes an exception for me, whereas translate animation works fine.Traherne
Nine Old doesn't work with fragment github.com/JakeWharton/NineOldAndroids/issues/43Peak
In case it helps others, if you want your animation to reverse when you back out of the fragment then specify all 4 parameters: ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right, R.anim.slide_in_right, R.anim.slide_out_left);Entomo
Please note that by using fragmentTransaction.replace(), you may be causing fragments to hit lifecycle events unnecessarily when the user presses the back button as compared to fragmentTransaction.add(). But, if you use .add(), you're not going to get as nice of an animation :) See here: https://mcmap.net/q/92389/-difference-between-add-replace-and-addtobackstackGaiser
Is there a built-in transition that is already used for activities, which I can use for fragments too?Triparted
S
259

If you don't have to use the support library then have a look at Roman's answer.

But if you want to use the support library you have to use the old animation framework as described below.

After consulting Reto's and blindstuff's answers I have gotten the following code working.

The fragments appear sliding in from the right and sliding out to the left when back is pressed.

FragmentManager fragmentManager = getSupportFragmentManager();

FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);

CustomFragment newCustomFragment = CustomFragment.newInstance();
transaction.replace(R.id.fragment_container, newCustomFragment );
transaction.addToBackStack(null);
transaction.commit();

The order is important. This means you must call setCustomAnimations() before replace() or the animation will not take effect!

Next these files have to be placed inside the res/anim folder.

enter.xml:

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

exit.xml:

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="-100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_enter.xml:

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="-100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_exit.xml:

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

The duration of the animations can be changed to any of the default values like @android:integer/config_shortAnimTime or any other number.

Note that if in between fragment replacements a configuration change happens (for example rotation) the back action isn't animated. This is a documented bug that still exists in the rev 20 of the support library.

Saveall answered 5/7, 2013 at 12:7 Comment(6)
This just saved me. Note, pay attention to the order is important, which, naturally, I missed the first time. This means you must call setCustomAnimations() before replace().Chaumont
I tried to implement on my fragments.I wrote everything as you mentioned but logcat says :unknow animator name translate How can I overcome this issue? By the way I'm calling my fragment on Navigation Drawer(Sliding Menu)Excursion
Works great but it turns out that building this with build tools 21.1 generates an error saying "Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])". I suggest editing the filenames in the answer to pop_enter.xml and pop_exit.xml.Maenad
Great solution and it works great when i press the back button. I just have one question: If i want to create a custom backButton, what code should i call to replicate the behaviour from the back button?Lindane
Thomas if you want to back, you should implemented this form: .setCustomAnimations(R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)Pyrognostics
@dmanargias, This is solution is working for me Too. I even tried slide up/ down and fade in/ out transition. But I'm getting a white screen, when the fragments are animating. This is happening only when I set animation. I tried with a dummy fragment, to check whether it is because of delay in view creation. But, white screen can be seen in this case too. Has anyone else faced similar issueJaniculum
D
28

I'd highly suggest you use this instead of creating the animation file because it's a much better solution. Android Studio already provides default animation you can use without creating any new XML file. The animations' names are android.R.anim.slide_in_left and android.R.anim.slide_out_right and you can use them as follows:

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

Dagney answered 22/9, 2017 at 5:17 Comment(2)
android.R... "Android Studio Provides default animation",that's not for android studio it can work in eclipse too,android.R is android specific.And by the way you didn't share the information what apis have this.Because stuff on android.R are different on different apis.Obi
@stevemoretz thaxs bro I agreed your point.. I will correct and update my answer...Dagney
M
5

My modified support library supports using both View animations (i.e. <translate>, <rotate>) and Object Animators (i.e. <objectAnimator>) for Fragment Transitions. It is implemented with NineOldAndroids. Refer to my documentation on github for details.

Mcabee answered 20/3, 2014 at 1:18 Comment(0)
A
2

As for me, i need the view diraction:

in -> swipe from right

out -> swipe to left

Here works for me code:

slide_in_right.xml

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

slide_out_left.xml

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

transaction code:

inline fun FragmentActivity.setContentFragment(
        containerViewId: Int,
        backStack: Boolean = false,
        isAnimate: Boolean = false,
        f: () -> Fragment

): Fragment? {
    val manager = supportFragmentManager
    return f().apply {
        manager.beginTransaction().let {
            if (isAnimate)
                it.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)

            if (backStack) {
                it.replace(containerViewId, this, "Fr").addToBackStack("Fr").commit()
            } else {
                it.replace(containerViewId, this, "Fr").commit()
            }
        }
    }
}
Ahoy answered 19/3, 2019 at 11:8 Comment(2)
Android seems to be flickering the transitions with those animations (specially the translate ones)Blount
@GabrielDeOliveiraRohden as for me not in all cassesAhoy
P
0

I solve this the way Below

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment
Pica answered 25/2, 2015 at 9:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.