注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。
原文链接: http://developer.android.com/training/animation/cardflip.html
这一节课将向您展示如何用自定义的fragment动画来实现翻牌动画(Card Flip)。翻牌动画是在视图切换的时候以翻牌形式为过渡动画的效果,其如下所示:
如果你希望略过这部分内容直接看代码样例,可以直接 下载 样例代码,然后选择淡入淡出动画的例子。下面的文件是实现代码:
-
src/CardFlipActivity.java
-
animator/card_flip_right_in.xml
-
animator/card_flip_right_out.xml
-
animator/card_flip_left_in.xml
-
animator/card_flip_left_out.xml
-
layout/fragment_card_back.xml
-
layout/fragment_card_front.xml
一). 创建动画执行器
要创建翻牌动画,在“卡片”移出或者移入时,你需要两个动画执行器(Animator)。
card_flip_left_in.xml
< 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 >
card_flip_left_out.xml
< 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 >
card_flip_right_in.xml
< 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" />
card_flip_right_out.xml
< 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 >
二). 创建视图
“卡片”的每一面是任何你希望的相互独立的内容,比如两屏的文字,两幅图片,或者任何视图的组合。接下来你就需要后面需要增加动画的fragment的两个布局。下面卡片其中一面的布局:
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:layout_height ="match_parent" android:orientation ="vertical" android:background ="#a6c" android:padding ="16dp" android:gravity ="bottom" > < TextView android:id ="@android:id/text1" style ="?android:textAppearanceLarge" android:textStyle ="bold" android:textColor ="#fff" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:text ="@string/card_back_title" /> < TextView style ="?android:textAppearanceSmall" android:textAllCaps ="true" android:textColor ="#80ffffff" android:textStyle ="bold" android:lineSpacingMultiplier ="1.2" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:text ="@string/card_back_description" /> </ LinearLayout >
卡牌的另一面显示一幅图片:
< ImageView xmlns:android ="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:layout_height ="match_parent" android:src ="@drawable/image1" android:scaleType ="centerCrop" android:contentDescription ="@string/description_image_1" />
三). 创建Fragment
为卡片的正反面创建fragment。这些类返回你之前在每个fragment中的
onCreateView()
方法中创建的布局。你可以在这些
fragment
的父
activity
(你期望显示卡牌的地方)创建这些
fragment
的实例。下面的代码展示了一个包含有
fragment
内部类的
activity
类:
public class CardFlipActivity extends Activity { ... /** * A fragment representing the front of the card. */ public class CardFrontFragment extends Fragment { @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 class CardBackFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_card_back, container, false ); } } }
四). 卡片翻转动画
现在,你需要展示一个父activity中的fragment。要这么做,首先为你的activity创建布局。下面的例子创建了一个 FrameLayout ,你可以在运行时添加fragment。
< FrameLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:id ="@+id/container" android:layout_width ="match_parent" android:layout_height ="match_parent" />
在activity的代码中,将视图设置为你刚才创建的布局。也可以展示一个创建activity时默认的fragment,下面的代码展示了如何显示默认的卡牌的正面:
public class CardFlipActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_activity_card_flip); if (savedInstanceState == null ) { getFragmentManager() .beginTransaction() .add(R.id.container, new CardFrontFragment()) .commit(); } } ... }
现在你已经有了卡牌的正面,你可以在某个时间通过卡牌反面的动画显示卡牌的背面。创建一个方法来显示卡牌的另一面,它做如下几件事情:
设置你之前为fragment切换所创建的自定义动画。
用新的fragment替换当前显示的fragment,并用你创建的自定义动画来执行这次动画切换。
将之前显示的fragment添加到回退栈中,所以当用户按下返回键时,卡片会翻转回来。
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(); }