编写:XizhiXu - 原文:http://developer.android.com/training/animation/cardflip.html
这节课展示如何使用自定义Fragment动画实现Card翻转动画。Card翻转动画通过模拟Card翻转的效果实现view内容的切换。
下面是card翻转动画的样子:
如果你想直接查看整个例子,下载并运行App样例然后选择Card翻转例子。查看下列文件中的代码实现:
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
创建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. --> <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" /> </set>
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>
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
<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" />
为Card正反面创建Fragment,这些类从 onCreateView() 方法中分别为每个Framgent返回你之前创建的布局。在想要显示Card的父Activity中,我们可以创建对应的Fragment 实例。下面的例子展示父Activity内嵌套的Fragment:
onCreateView()
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的布局。下面例子创建了一个可以在运行时添加Fragment的 FrameLayout。
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 { @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到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(); }
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8