Thursday, March 15, 2012

Putting simple transition effect to fragments

Nowadays it's recommended to use Fragments, even when developing non-tablet apps.

One of the first thing I notice when moving between fragments is that the user immediately see the new fragments without any transition animation. We want to add some kind of animation, unfortunately the FragmentTransaction documentation is very scarce.

After experiments, this works even when using v4 Support Library:

It happens that we need to consider several things:
  1. setTransition and setTransitionStyle is confusing and useless. Forget them.
  2. setCustomAnimations is the way to go. But you have to call it before you call add/remove/hide or similar operations.
  3. The resource ids passed to setCustomAnimations will be decoded using AnimationUtils.loadAnimation(). So you can pass anim resources (the old-style animations). I haven't tested whether the new animator resources work.
In order to "push" a fragment as if you were starting a new Activity using startActivity, call the following:


public static void moveForward(FragmentManager fm, Fragment current, Fragment newer, String backstackName, boolean allowStateLoss) {
 FragmentTransaction ft = fm.beginTransaction();
 ft.setCustomAnimations(android.R.anim.fade_in, 0, android.R.anim.fade_in, 0);
 ft.hide(current);
 ft.add(android.R.id.content, newer);
 ft.addToBackStack(backstackName);
 if (allowStateLoss) {
  ft.commitAllowingStateLoss();
 } else {
  ft.commit();
 }
}

For example, from the current Fragment, you want to transition to the AnotherFragment, call the method above as follows:

moveForward(getFragmentManager(), this, new AnotherFragment(), "another", false)

Bonus: If you call the above method after returning from other applications (for example inside onActivityResult), make sure to pass true to allow state loss, or your app will crash. It's not discussed here why =).