效果图:
实现 :
一:创建Animator
如图:
第一个卡片要向左翻转消失 ,向右翻转出现
第二张卡片向右翻转消失,向左翻转出现 。
首先第二张向左翻转进入 card_flip_left_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--旋转之前,立刻设置透明度alpha为0-->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!--旋转-->
<objectAnimator
android:valueFrom="-180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!--旋转中途(时间偏移量取决于startOffset属性)设置透明度为1-->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
card_flip_left_out.xml 第一张向左翻转消失
card_flip_right_in.xml 第一张向右翻转进入<set xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 旋转. --> <objectAnimator android:valueFrom="0" android:valueTo="180" android:propertyName="rotationY" android:interpolator="@android:interpolator/accelerate_decelerate" android:duration="@integer/card_flip_time_full" /> <!--旋转中途(时间偏移量取决于startOffset属性)设置透明度为0--> <objectAnimator android:valueFrom="1.0" android:valueTo="0.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"> <!--旋转之前,立刻设置透明度alpha为0--> <objectAnimator android:valueFrom="1.0" android:valueTo="0.0" android:propertyName="alpha" android:duration="0" /> <!-- 旋转. --> <objectAnimator android:valueFrom="180" android:valueTo="0" android:propertyName="rotationY" android:interpolator="@android:interpolator/accelerate_decelerate" android:duration="@integer/card_flip_time_full" /> <!--旋转中途(时间偏移量取决于startOffset属性)设置透明度为1--> <objectAnimator android:valueFrom="0.0" android:valueTo="1.0" android:propertyName="alpha" android:startOffset="@integer/card_flip_time_half" android:duration="1" />
第二向右翻转消失 card_flip_right_out.xml<set xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 旋转. --> <objectAnimator android:valueFrom="0" android:valueTo="-180" android:propertyName="rotationY" android:interpolator="@android:interpolator/accelerate_decelerate" android:duration="@integer/card_flip_time_full" /> <!--旋转中途(时间偏移量取决于startOffset属性)设置透明度为0--> <objectAnimator android:valueFrom="1.0" android:valueTo="0.0" android:propertyName="alpha" android:startOffset="@integer/card_flip_time_half" android:duration="1" /> </set>
二.创建View
第一个fragment布局
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/cardfront"/> </FrameLayout>
第二个fragment 布局
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/cardback"/> </FrameLayout>
三 创建Fragment
CardFrontFragment
@SuppressLint("NewApi") public static class CardFrontFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_cardfront, container, false); } }
CardBackFragment@SuppressLint("NewApi") public static class CardBackFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_cardback, container, false); } }
四 应用翻转动画
Activity 的布局<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout>
整体代码
package cardflip; import com.lt.timesofimagereading.R; import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager.OnBackStackChangedListener; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.NavUtils; import android.util.Log; import android.view.Choreographer.FrameCallback; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationSet; @SuppressLint("NewApi") public class CardFlipActivity extends Activity implements OnBackStackChangedListener { private Handler mHandler = new Handler(); private boolean mShowingBack = false; @SuppressLint("NewApi") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_card_flip); if (savedInstanceState == null) { getFragmentManager().beginTransaction() .add(R.id.container, new CardFrontFragment()).commit(); } else { mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0); } } @SuppressLint("NewApi") public static class CardFrontFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_cardfront, container, false); } } @SuppressLint("NewApi") public static class CardBackFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_cardback, container, false); } } @SuppressLint("NewApi") @Override public boolean onCreateOptionsMenu(Menu menu) { 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(); if (mShowingBack) { mShowingBack = false; } return true; } return super.onOptionsItemSelected(item); } @SuppressLint("NewApi") private void flipCard() { // if (mShowingBack) { // getFragmentManager().popBackStack(); // return; // } Log.e("Acount", getFragmentManager().getBackStackEntryCount() + ""); if (getFragmentManager().getBackStackEntryCount() == 1) { getFragmentManager().popBackStack(); } else { // 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(); } }); } @SuppressLint("NewApi") @Override public void onBackStackChanged() { mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0); // When the back stack changes, invalidate the options menu (action // bar). invalidateOptionsMenu(); } @Override public void onBackPressed() { super.onBackPressed(); } }