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"> </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<set xmlns:android="http://schemas.android.com/apk/res/android"> 99 <!-- Before rotating, immediately set the alpha to 0. --> 100 <objectAnimator 101 android:valueFrom="1.0" 102 android:valueTo="0.0" 103 android:propertyName="alpha" 104 android:duration="0" /> 105 106 <!-- Rotate. --> 107 <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" /> 113 114 <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> 115 <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" /> 121</set> 122</pre> 123 <h4> 124 card_flip_left_out.xml 125 </h4> 126 <pre> 127<set xmlns:android="http://schemas.android.com/apk/res/android"> 128 <!-- Rotate. --> 129 <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" /> 135 136 <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> 137 <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" /> 143</set> 144 </pre> 145 <h4> 146 card_flip_right_in.xml 147 </h4> 148 <pre> 149<set xmlns:android="http://schemas.android.com/apk/res/android"> 150 <!-- Before rotating, immediately set the alpha to 0. --> 151 <objectAnimator 152 android:valueFrom="1.0" 153 android:valueTo="0.0" 154 android:propertyName="alpha" 155 android:duration="0" /> 156 157 <!-- Rotate. --> 158 <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" /> 164 165 <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> 166 <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" /> 172</set> 173 174</pre> 175 <h4> 176 card_flip_right_out.xml 177 </h4> 178 <pre> 179<set xmlns:android="http://schemas.android.com/apk/res/android"> 180 <!-- Rotate. --> 181 <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" /> 187 188 <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> 189 <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" /> 195</set> 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<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"> 215 216 <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" /> 223 224 <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" /> 232 233</LinearLayout> 234</pre> 235<p> 236and the other side of the card that displays an {@link android.widget.ImageView}: 237</p> 238<pre> 239<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" /> 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 @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 @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<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" /> 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 @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