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.