Home | History | Annotate | Download | only in animation
      1 page.title=Displaying Card Flip Animations
      2 trainingnavtop=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>
    236 and 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>
    257 public 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>
    306 public 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>
    339 private 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