展示Card翻转动画
编写:XizhiXu - 原文:http://developer.android.com/training/animation/cardflip.html
这节课展示如何使用自定义Fragment动画实现Card翻转动画。Card翻转动画通过模拟Card翻转的效果实现view内容的切换。
下面是card翻转动画的样子:
如果你想直接查看整个例子,下载并运行App样例然后选择Card翻转例子。查看下列文件中的代码实现:
src/CardFlipActivity.javaanimator/card_flip_right_in.xmlanimator/card_flip_right_out.xmlanimator/card_flip_left_in.xmlanimator/card_flip_left_out.xmllayout/fragment_card_back.xmllayout/fragment_card_front.xml
创建Animator
创建Card翻转动画,我们需要两个Animator。一个让正面的card的右侧向左翻转渐出,一个让背面的Card向右翻转渐入。我们还需要两个 Animator让背面的card的右侧向左翻转渐入,一个让向右翻转渐入。
card_flip_left_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"><!-- Before rotating, immediately set the alpha to 0. --><objectAnimatorandroid:valueFrom="1.0"android:valueTo="0.0"android:propertyName="alpha"android:duration="0" /><!-- Rotate. --><objectAnimatorandroid: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. --><objectAnimatorandroid: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. --><objectAnimatorandroid: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. --><objectAnimatorandroid: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. --><objectAnimatorandroid:valueFrom="1.0"android:valueTo="0.0"android:propertyName="alpha"android:duration="0" /><!-- Rotate. --><objectAnimatorandroid: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. --><objectAnimatorandroid:valueFrom="0.0"android:valueTo="1.0"android:propertyName="alpha"android:startOffset="@integer/card_flip_time_half"android:duration="1" /></set>
card_flip_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"><!-- Rotate. --><objectAnimatorandroid: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. --><objectAnimatorandroid:valueFrom="1.0"android:valueTo="0.0"android:propertyName="alpha"android:startOffset="@integer/card_flip_time_half"android:duration="1" /></set>
创建View
Card的每一面是一个独立的布局,比如两屏文字,两张图片,或者任何View的组合。然后我们将在应用动画的Fragment里面用到这两个布局。下面的布局创建了展示文本Card的一面:
<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>
Card另一面显示一个 ImageView:
<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
为Card正反面创建Fragment,这些类从 onCreateView() 方法中分别为每个Framgent返回你之前创建的布局。在想要显示Card的父Activity中,我们可以创建对应的Fragment 实例。下面的例子展示父Activity内嵌套的Fragment:
public class CardFlipActivity extends Activity {.../*** A fragment representing the front of the card.*/public class CardFrontFragment extends Fragment {@Overridepublic 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 {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_card_back, container, false);}}}
应用card翻转动画
现在,我们需要在父Activity中展示Fragment。为此,首先创建Activity的布局。下面例子创建了一个可以在运行时添加Fragment的 FrameLayout。
<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代码中,把先前创建的布局设置成其ContentVew。当Activity创建时展示一个默认的Fragment是个不错的注意。所以下面的Activity样例表明了如何默认显示卡片正面:
public class CardFlipActivity extends Activity {@Overrideprotected 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到Fragment的回退栈(back stack)中,所以当用户按下 Back 键时,Card会翻转回来。
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();}
