本节课讲解如何以定制的fragment动画来实现卡片翻转动画。
创建animator
创建卡片翻转的动画。你需要两个animator,用于卡片的正面向左向外翻转,然后从左向内翻转。你同意需要两个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), 设置透明度alpha 为 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"> <!-- 旋转. --> <objectAnimator android:valueFrom="0" android:valueTo="180" android:propertyName="rotationY" android:interpolator="@android:interpolator/accelerate_decelerate" android:duration="@integer/card_flip_time_full" /> <!-- 旋转过程中 (见startOffset), 设置透明度alpha 为 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"> <!-- 在旋转前,立即将透明度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), 把透明度alpha设为 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), 设置 透明度alpha 为 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
"卡片"的每一面是一个独立的layout布局,能够装下你想放置的任何内容,比如说两屏文字,或者两张图片,或者任何view的组合。然后你可以在要翻转的fragment中使用这两个定义好的layout布局。下面的layout布局创建了卡片的一面,用于显示文字。
<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:
<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类。这两个类在其各自的onCreateView()方法中返回你刚刚在前面创建的布局。当你想展示卡片时,你就可以在父activity中创建该fragment的实例。下面的例子在父activity中创建fragment内部类。
public class CardFlipActivity extends Activity { ... /** * 代表卡片正面的fragment */ 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); } } /** * 代表卡片背面的fragment */ 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的layout。下面的例子就是一个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代码中,把content view设置为你刚刚创建的layout。在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回退栈中,这养当用户按下回退键,卡片会翻转回去。
private void flipCard() { if (mShowingBack) { getFragmentManager().popBackStack(); return; } // 翻向背面. mShowingBack = true; // 创建并提交一个fragment事务,添加卡片背面的fragment,使用定制动画,使其成为fragment manager的回退栈的一部分。 getFragmentManager() .beginTransaction() // 用代表转向卡片背面和转向卡片正面的animator资源取代默认的fragment动画。 .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) // 用代表下一页的fragment(indicated by the just-incremented currentPage variable)取代当前正在container view中显示的fragment。 .replace(R.id.container, new CardBackFragment()) // 把该事务提交到回退栈,当用户按回退键时返回到卡片正面。 .addToBackStack(null) // 提交事务. .commit(); }