Honeycomb GMail animation mystery

There are a lot of questions on the Internet like these:

http://stackoverflow.com/questions/4817900/android-fragments-and-animation
http://stackoverflow.com/questions/5327636/animating-fragments-and-the-back-stack

GMail Honeycomb Android slide animation

If you are looking for a sample code – this post is for you.

Everybody wants to implement slide-in/slide-out animations like in GMail Tablet client. They try to use fragment animations (setCustomAnimations for FragmentTransaction). But if you take a deep look into GMail client implementation – they use LinearLayout and ObjectAnimator.

The code is quite simple – you just change left margin of the root view + change width of the right view.

package com.fragment.test;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;

public class FragmentAnimationTestActivity extends Activity implements Fragment2.FragmentResultListener {

    private static final TimeInterpolator sCollapseInterpolator = new DecelerateInterpolator(2.5F);

    private View mPanel1;
    private View mPanel2;
    private View mLayout;

    boolean isCollapsed;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mLayout = findViewById(R.id.l1);
        mPanel1 = findViewById(R.id.fragment1);
        mPanel2 = findViewById(R.id.fragment2);
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.fragment1, Fragment1.newInstance(), "f1");
        ft.replace(R.id.fragment2, Fragment2.newInstance(this), "f2");
        ft.commit();
    }

    public int getPanelLeft() {
        return ((ViewGroup.MarginLayoutParams) mLayout.getLayoutParams()).leftMargin;
    }

    public void setPanelLeft(int paramInt) {
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mLayout.getLayoutParams();
        lp.leftMargin = paramInt;
        mLayout.setLayoutParams(lp);
    }

    public int getPanel2W() {
        return ((ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams()).width;
    }

    public void setPanel2W(int paramInt) {
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams();
        lp.width = paramInt;
        mPanel2.setLayoutParams(lp);
    }

    @Override
    public void onBtnClick() {
        if (isCollapsed) {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", -300, 0);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 1280, 980);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
                    arrayOfPropertyValuesHolder).setDuration(400);
            localObjectAnimator.setInterpolator(sCollapseInterpolator);
            localObjectAnimator.start();
        } else {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", 0, -300);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 980, 1280);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
                    arrayOfPropertyValuesHolder).setDuration(400);
            localObjectAnimator.setInterpolator(sCollapseInterpolator);
            localObjectAnimator.start();
        }
        isCollapsed = !isCollapsed;
    }

}

Of course, you can calculate all values dynamically. This is just a quick ugly sample. Full source code is available here.

Happy tabletting! :)

//DL

Share
  • Alex

    Exelent sample.
    Do you know how drop a shadow, over the left view ?

  • Andrew

    Thanks for this! How would we make this proguard friendly? I think proguard obfuscates the name of the get and set methods

  • Pingback: Complete Working Sample of the Gmail Three-Fragment Animation Scenario?

  • Pingback: Complete Working Sample of the Gmail Three-Fragment Animation Scenario? - feed99

  • Naveen

    Very nice sample, please help me suppose I have two Fragment1, and Fragment2 with one container screen, There is button on Fragment1, after clicking the button I want navigate a another fragment activity, there is need of back button on that right fragment, user can click back button and navigate prev container screen.

    how to implement this approach, I am not getting a actual way for Implement this same code as per my need.

    As per this approach user can only able to access IDs of Left fragment and right fragment animation on right fragment button.

    I want separate button on left and right fragment for prev and next for load n- stack of fragment .

    Thanks,
    Naveen