FlipCard animation using Fragments in Android.

By | August 21, 2013

Hello all

I am back with fragments again. I know you have seen a lot of posts on fragments and fragment animation.

This one will be another useful post for you.

This post helps you to show a FlipCard animation using Fragments.

Let us see how can we do this.

At first I will show the activity that I am using to create Animation which contain two fragments for Front and Back Page.

CardFlipActivity.java

package com.example.cardflipanimation;
 
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.NavUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
 
public class CardFlipActivity extends Activity implements
        FragmentManager.OnBackStackChangedListener {
    /**
     * A handler object, used for deferring UI operations.
     */
    private Handler mHandler = new Handler();
 
    /**
     * Whether or not we're showing the back of the card (otherwise showing the
     * front).
     */
    private boolean mShowingBack = false;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_card_flip);
 
        if (savedInstanceState == null) {
            // If there is no saved instance state, add a fragment representing
            // the
            // front of the card to this activity. If there is saved instance
            // state,
            // this fragment will have already been added to the activity.
            getFragmentManager().beginTransaction()
                    .add(R.id.container, new CardFrontFragment()).commit();
        } else {
            mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
        }
 
        // Monitor back stack changes to ensure the action bar shows the
        // appropriate
        // button (either "photo" or "info").
        getFragmentManager().addOnBackStackChangedListener(this);
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
 
        // Add either a "photo" or "finish" button to the action bar, depending
        // on which page
        // is currently selected.
        MenuItem item = menu.add(Menu.NONE, R.id.action_flip, Menu.NONE,
                mShowingBack ? R.string.action_photo : R.string.action_info);
        item.setIcon(mShowingBack ? R.drawable.ic_action_photo
                : R.drawable.ic_action_info);
        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            // Navigate "up" the demo structure to the launchpad activity.
            // See http://developer.android.com/design/patterns/navigation.html
            // for more.
            NavUtils.navigateUpTo(this,
                    new Intent(this, CardFlipActivity.class));
            return true;
 
        case R.id.action_flip:
            flipCard();
            return true;
        }
 
        return super.onOptionsItemSelected(item);
    }
 
    private void flipCard() {
        if (mShowingBack) {
            getFragmentManager().popBackStack();
            return;
        }
 
        // Flip to the back.
 
        mShowingBack = true;
 
        // Create and commit a new fragment transaction that adds the fragment
        // for the back of
        // the card, uses custom animations, and is part of the fragment
        // manager's back stack.
 
        getFragmentManager().beginTransaction()
 
        // Replace the default fragment animations with animator resources
        // representing
        // rotations when switching to the back of the card, as well as animator
        // resources representing rotations when flipping back to the front
        // (e.g. when
        // the system Back button is pressed).
                .setCustomAnimations(R.animator.card_flip_right_in,
                        R.animator.card_flip_right_out,
                        R.animator.card_flip_left_in,
                        R.animator.card_flip_left_out)
 
                // Replace any fragments currently in the container view with a
                // fragment
                // representing the next page (indicated by the just-incremented
                // currentPage
                // variable).
                .replace(R.id.container, new CardBackFragment())
 
                // Add this transaction to the back stack, allowing users to
                // press Back
                // to get to the front of the card.
                .addToBackStack(null)
 
                // Commit the transaction.
                .commit();
 
        // Defer an invalidation of the options menu (on modern devices, the
        // action bar). This
        // can't be done immediately because the transaction may not yet be
        // committed. Commits
        // are asynchronous in that they are posted to the main thread's message
        // loop.
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                invalidateOptionsMenu();
            }
        });
    }
 
    @Override
    public void onBackStackChanged() {
        mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
 
        // When the back stack changes, invalidate the options menu (action
        // bar).
        invalidateOptionsMenu();
    }
 
    /**
     * A fragment representing the front of the card.
     */
    public static class CardFrontFragment extends Fragment {
        public CardFrontFragment() {
        }
 
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_card_front, container,
                    false);
        }
    }
 
    /**
     * A fragment representing the back of the card.
     */
    public static class CardBackFragment extends Fragment {
        public CardBackFragment() {
        }
 
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_card_back, container,
                    false);
        }
    }
}

Now the animations.
For that you have to create 4 xml animation files in the res/animator folder.

card_flip_left_in.xml
card_flip_left_out.xml
card_flip_right_in.xml
card_flip_right_out.xml

I will be listing these files in this order.

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Before rotating, immediately set the alpha to 0. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:duration="0" />
 
    <!-- Rotate. -->
    <objectAnimator
        android:valueFrom="-180"
        android:valueTo="0"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />
 
    <!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
    <objectAnimator
        android:valueFrom="0.0"
        android:valueTo="1.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Rotate. -->
    <objectAnimator android:valueFrom="0"
        android:valueTo="180"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full"></objectAnimator>
 
    <!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
    <objectAnimator android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1"></objectAnimator>
</set>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Before rotating, immediately set the alpha to 0. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:duration="0" />
 
    <!-- Rotate. -->
    <objectAnimator
        android:valueFrom="180"
        android:valueTo="0"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />
 
    <!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
    <objectAnimator
        android:valueFrom="0.0"
        android:valueTo="1.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Rotate. -->
    <objectAnimator
        android:valueFrom="0"
        android:valueTo="-180"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />
 
    <!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>

Inside the drawable folder put these images.

ic_action_info.png
ic_action_photo.png
image1.png

Put these inside the ids.xml folder inside the res/values folder.

<item type="id" name="action_next" />
<item type="id" name="action_flip" />

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <string name="app_name">CardFlipAnimation</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="action_info">Photo info</string>
    <string name="action_photo">View photo</string>
 
</resources>

And also integers.xml

<resources>
    <integer name="card_flip_time_full">300</integer>
    <integer name="card_flip_time_half">150</integer>
</resources>

Download the complete android source code from here.