• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Displaying Card Flip Animations
2trainingnavtop=true
3
4@jd:body
5    <div id="tb-wrapper">
6      <div id="tb">
7        <h2>
8          This lesson teaches you to
9        </h2>
10        <ol>
11          <li>
12            <a href="#animators">Create the Animators</a>
13          </li>
14          <li>
15            <a href="#views">Create the Views</a>
16          </li>
17          <li>
18            <a href="#fragment">Create the Fragment</a>
19          </li>
20          <li>
21            <a href="#animate">Animate the Card Flip</a>
22          </li>
23        </ol>
24        <h2>
25          Try it out
26        </h2>
27        <div class="download-box">
28          <a href="{@docRoot}shareables/training/Animations.zip" class=
29          "button">Download the sample app</a>
30          <p class="filename">
31            Animations.zip
32          </p>
33        </div>
34      </div>
35    </div>
36    <p> This lesson shows you how to do a card flip
37      animation with custom fragment animations.
38      Card flips animate between views of content by showing an animation that emulates
39      a card flipping over.
40    </p>
41    <p>Here's what a card flip looks like:
42    </p>
43
44    <div class="framed-galaxynexus-land-span-8">
45      <video class="play-on-hover" autoplay>
46        <source src="anim_card_flip.mp4" type="video/mp4">
47        <source src="anim_card_flip.webm" type="video/webm">
48        <source src="anim_card_flip.ogv" type="video/ogg">
49      </video>
50    </div>
51    <div class="figure-caption">
52      Card flip animation
53      <div class="video-instructions">&nbsp;</div>
54    </div>
55
56    <p>
57      If you want to jump ahead and see a full working example,
58      <a href="{@docRoot}shareables/training/Animations.zip">download</a> and
59      run the sample app and select the Card Flip example. See the following
60      files for the code implementation:
61    </p>
62    <ul>
63      <li>
64        <code>src/CardFlipActivity.java</code>
65      </li>
66      <li>
67        <code>animator/card_flip_right_in.xml</code>
68      </li>
69      <li>
70        <code>animator/card_flip_right_out.xml</code>
71      </li>
72      <li>
73        <code>animator/card_flip_left_in.xml</code>
74      </li>
75      <li>
76        <code>animator/card_flip_left_out.xml</code>
77      </li>
78      <li>
79        <code>layout/fragment_card_back.xml</code>
80      </li>
81      <li>
82        <code>layout/fragment_card_front.xml</code>
83      </li>
84    </ul>
85
86    <h2 id="animate">
87      Create the Animators
88    </h2>
89    <p>
90      Create the animations for the card flips. You'll need two animators for when the front
91      of the card animates out and to the left and in and from the left. You'll also need two animators
92      for when the back of the card animates in and from the right and out and to the right.
93    </p>
94    <h4>
95      card_flip_left_in.xml
96    </h4>
97<pre>
98&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
99    &lt;!-- Before rotating, immediately set the alpha to 0. --&gt;
100    &lt;objectAnimator
101        android:valueFrom="1.0"
102        android:valueTo="0.0"
103        android:propertyName="alpha"
104        android:duration="0" /&gt;
105
106    &lt;!-- Rotate. --&gt;
107    &lt;objectAnimator
108        android:valueFrom="-180"
109        android:valueTo="0"
110        android:propertyName="rotationY"
111        android:interpolator="@android:interpolator/accelerate_decelerate"
112        android:duration="@integer/card_flip_time_full" /&gt;
113
114    &lt;!-- Half-way through the rotation (see startOffset), set the alpha to 1. --&gt;
115    &lt;objectAnimator
116        android:valueFrom="0.0"
117        android:valueTo="1.0"
118        android:propertyName="alpha"
119        android:startOffset="@integer/card_flip_time_half"
120        android:duration="1" /&gt;
121&lt;/set&gt;
122</pre>
123    <h4>
124      card_flip_left_out.xml
125    </h4>
126    <pre>
127&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
128    &lt;!-- Rotate. --&gt;
129    &lt;objectAnimator
130        android:valueFrom="0"
131        android:valueTo="180"
132        android:propertyName="rotationY"
133        android:interpolator="@android:interpolator/accelerate_decelerate"
134        android:duration="@integer/card_flip_time_full" /&gt;
135
136    &lt;!-- Half-way through the rotation (see startOffset), set the alpha to 0. --&gt;
137    &lt;objectAnimator
138        android:valueFrom="1.0"
139        android:valueTo="0.0"
140        android:propertyName="alpha"
141        android:startOffset="@integer/card_flip_time_half"
142        android:duration="1" /&gt;
143&lt;/set&gt;
144    </pre>
145    <h4>
146      card_flip_right_in.xml
147    </h4>
148    <pre>
149&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
150    &lt;!-- Before rotating, immediately set the alpha to 0. --&gt;
151    &lt;objectAnimator
152        android:valueFrom="1.0"
153        android:valueTo="0.0"
154        android:propertyName="alpha"
155        android:duration="0" /&gt;
156
157    &lt;!-- Rotate. --&gt;
158    &lt;objectAnimator
159        android:valueFrom="180"
160        android:valueTo="0"
161        android:propertyName="rotationY"
162        android:interpolator="@android:interpolator/accelerate_decelerate"
163        android:duration="@integer/card_flip_time_full" /&gt;
164
165    &lt;!-- Half-way through the rotation (see startOffset), set the alpha to 1. --&gt;
166    &lt;objectAnimator
167        android:valueFrom="0.0"
168        android:valueTo="1.0"
169        android:propertyName="alpha"
170        android:startOffset="@integer/card_flip_time_half"
171        android:duration="1" /&gt;
172</set>
173
174</pre>
175    <h4>
176      card_flip_right_out.xml
177    </h4>
178    <pre>
179&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
180    &lt;!-- Rotate. --&gt;
181    &lt;objectAnimator
182        android:valueFrom="0"
183        android:valueTo="-180"
184        android:propertyName="rotationY"
185        android:interpolator="@android:interpolator/accelerate_decelerate"
186        android:duration="@integer/card_flip_time_full" /&gt;
187
188    &lt;!-- Half-way through the rotation (see startOffset), set the alpha to 0. --&gt;
189    &lt;objectAnimator
190        android:valueFrom="1.0"
191        android:valueTo="0.0"
192        android:propertyName="alpha"
193        android:startOffset="@integer/card_flip_time_half"
194        android:duration="1" /&gt;
195&lt;/set&gt;
196</pre>
197    <h2 id="views">
198      Create the Views
199    </h2>
200    <p>
201      Each side of the "card" is a separate layout that can contain any content you want,
202      such as two screens of text, two images, or any combination of views to flip between. You'll then
203      use the two layouts in the fragments that you'll later animate. The following layouts
204      create one side of a card that shows text:
205    </p>
206
207    <pre>
208&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
209    android:layout_width="match_parent"
210    android:layout_height="match_parent"
211    android:orientation="vertical"
212    android:background="#a6c"
213    android:padding="16dp"
214    android:gravity="bottom"&gt;
215
216    &lt;TextView android:id="@android:id/text1"
217        style="?android:textAppearanceLarge"
218        android:textStyle="bold"
219        android:textColor="#fff"
220        android:layout_width="match_parent"
221        android:layout_height="wrap_content"
222        android:text="@string/card_back_title" /&gt;
223
224    &lt;TextView style="?android:textAppearanceSmall"
225        android:textAllCaps="true"
226        android:textColor="#80ffffff"
227        android:textStyle="bold"
228        android:lineSpacingMultiplier="1.2"
229        android:layout_width="match_parent"
230        android:layout_height="wrap_content"
231        android:text="@string/card_back_description" /&gt;
232
233&lt;/LinearLayout&gt;
234</pre>
235<p>
236and the other side of the card that displays an {@link android.widget.ImageView}:
237</p>
238<pre>
239&lt;ImageView xmlns:android="http://schemas.android.com/apk/res/android"
240    android:layout_width="match_parent"
241    android:layout_height="match_parent"
242    android:src="@drawable/image1"
243    android:scaleType="centerCrop"
244    android:contentDescription="@string/description_image_1" /&gt;
245</pre>
246    <h2 id="fragment">
247      Create the Fragment
248    </h2>
249    <p>
250      Create fragment classes for the front and back of the card. These classes return the layouts
251      that you created previously in the {@link android.app.Fragment#onCreateView onCreateView()} method
252      of each fragment. You can then create instances of this fragment in the parent activity
253      where you want to show the card. The following example shows nested fragment classes inside
254      of the parent activity that uses them:
255    </p>
256    <pre>
257public class CardFlipActivity extends Activity {
258    ...
259    /**
260     * A fragment representing the front of the card.
261     */
262    public class CardFrontFragment extends Fragment {
263        &#64;Override
264        public View onCreateView(LayoutInflater inflater, ViewGroup container,
265                Bundle savedInstanceState) {
266            return inflater.inflate(R.layout.fragment_card_front, container, false);
267        }
268    }
269
270    /**
271     * A fragment representing the back of the card.
272     */
273    public class CardBackFragment extends Fragment {
274        &#64;Override
275        public View onCreateView(LayoutInflater inflater, ViewGroup container,
276                Bundle savedInstanceState) {
277            return inflater.inflate(R.layout.fragment_card_back, container, false);
278        }
279    }
280}
281</pre>
282    <h2 id="animate">
283      Animate the Card Flip
284    </h2>
285
286    <p> Now, you'll need to display the fragments inside of a parent activity.
287    To do this, first create the layout for your activity. The following example creates a
288    {@link android.widget.FrameLayout} that you
289    can add fragments to at runtime:</p>
290
291    <pre>
292&lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
293    android:id="@+id/container"
294    android:layout_width="match_parent"
295    android:layout_height="match_parent" /&gt;
296</pre>
297
298    <p>In the activity code, set the content view to be the layout that you just created. It's also
299      good idea to show a default fragment when the activity is created, so the following example
300      activity shows you how to display the front of the card by default:
301    </p>
302
303
304
305<pre>
306public class CardFlipActivity extends Activity {
307
308    &#64;Override
309    protected void onCreate(Bundle savedInstanceState) {
310        super.onCreate(savedInstanceState);
311        setContentView(R.layout.activity_activity_card_flip);
312
313        if (savedInstanceState == null) {
314            getFragmentManager()
315                    .beginTransaction()
316                    .add(R.id.container, new CardFrontFragment())
317                    .commit();
318        }
319    }
320    ...
321}
322</pre>
323    <p>
324      Now that you have the front of the card showing, you can show the back of the card
325      with the flip animation at an appropriate time. Create a method to show the other
326      side of the card that does the following things:
327    </p>
328    <ul>
329      <li>Sets the custom animations that you created earlier for the fragment transitions.
330      </li>
331      <li>Replaces the currently displayed fragment with a new fragment and animates this event
332      with the custom animations that you created.
333      </li>
334      <li>Adds the previously displayed fragment to the fragment back stack
335      so when the user presses the <em>Back</em> button, the card flips back over.
336      </li>
337    </ul>
338    <pre>
339private void flipCard() {
340    if (mShowingBack) {
341        getFragmentManager().popBackStack();
342        return;
343    }
344
345    // Flip to the back.
346
347    mShowingBack = true;
348
349    // Create and commit a new fragment transaction that adds the fragment for the back of
350    // the card, uses custom animations, and is part of the fragment manager's back stack.
351
352    getFragmentManager()
353            .beginTransaction()
354
355            // Replace the default fragment animations with animator resources representing
356            // rotations when switching to the back of the card, as well as animator
357            // resources representing rotations when flipping back to the front (e.g. when
358            // the system Back button is pressed).
359            .setCustomAnimations(
360                    R.animator.card_flip_right_in, R.animator.card_flip_right_out,
361                    R.animator.card_flip_left_in, R.animator.card_flip_left_out)
362
363            // Replace any fragments currently in the container view with a fragment
364            // representing the next page (indicated by the just-incremented currentPage
365            // variable).
366            .replace(R.id.container, new CardBackFragment())
367
368            // Add this transaction to the back stack, allowing users to press Back
369            // to get to the front of the card.
370            .addToBackStack(null)
371
372            // Commit the transaction.
373            .commit();
374}
375</pre>
376