注:本文翻译自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();
}

