Home | History | Annotate | Download | only in sgv
      1 // Copyright 2013 Google Inc. All Rights Reserved.
      2 
      3 package com.android.deskclock.widget.sgv;
      4 
      5 import android.R.interpolator;
      6 import android.animation.Animator;
      7 import android.animation.Animator.AnimatorListener;
      8 import android.animation.AnimatorListenerAdapter;
      9 import android.animation.ObjectAnimator;
     10 import android.content.Context;
     11 import android.graphics.Point;
     12 import android.view.View;
     13 import android.view.WindowManager;
     14 import android.view.animation.AnimationUtils;
     15 import android.view.animation.Interpolator;
     16 
     17 
     18 import java.util.List;
     19 
     20 public class SgvAnimationHelper {
     21 
     22     /**
     23      * Supported entrance animations for views in the {@link StaggeredGridView}.
     24      */
     25     public enum AnimationIn {
     26         NONE,
     27         // Fly in all views from the bottom of the screen
     28         FLY_UP_ALL_VIEWS,
     29         // New views expand into view from height 0.  Existing views are updated and translated
     30         // to their new positions if appropriate.
     31         EXPAND_NEW_VIEWS,
     32         // New views expand into view from height 0.  Existing views are updated and translated
     33         // to their new positions if appropriate.  This animation is done for all views
     34         // simultaneously without a cascade effect.
     35         EXPAND_NEW_VIEWS_NO_CASCADE,
     36         // New views are flown in from the bottom.  Existing views are updated and translated
     37         // to their new positions if appropriate.
     38         FLY_IN_NEW_VIEWS,
     39         // New views are slid in from the side.  Existing views are updated and translated
     40         // to their new positions if appropriate.
     41         SLIDE_IN_NEW_VIEWS,
     42         // Fade in all new views
     43         FADE,
     44     }
     45 
     46     /**
     47      * Supported exit animations for views in the {@link StaggeredGridView}.
     48      */
     49     public enum AnimationOut {
     50         NONE,
     51         // Stale views are faded out of view.  Existing views are then updated and translated
     52         // to their new positions if appropriate.
     53         FADE,
     54         // Stale views are dropped to the bottom of the screen.  Existing views are then updated
     55         // and translated to their new positions if appropriate.
     56         FLY_DOWN,
     57         // Stale views are slid to the side of the screen.  Existing views are then updated
     58         // and translated to their new positions if appropriate.
     59         SLIDE,
     60         // Stale views are collapsed to height 0.  Existing views are then updated
     61         // and translated to their new positions if appropriate.
     62         COLLAPSE
     63     }
     64 
     65     private static Interpolator sDecelerateQuintInterpolator;
     66 
     67     private static final int ANIMATION_LONG_SCREEN_SIZE = 1600;
     68     private static final int ANIMATION_MED_SCREEN_SIZE = 1200;
     69 
     70     // Duration of an individual animation when the children of the grid are laid out again. These
     71     // are measured in milliseconds and based on the height of the screen.
     72     private static final int ANIMATION_SHORT_DURATION = 400;
     73     private static final int ANIMATION_MED_DURATION = 450;
     74     private static final int ANIMATION_LONG_DURATION = 500;
     75 
     76     public static final float ANIMATION_ROTATION_DEGREES = 25.0f;
     77 
     78     /**
     79      * Duration of an individual animation when the children of the grid are laid out again.
     80      * This is measured in milliseconds.
     81      */
     82     private static int sAnimationDuration = ANIMATION_MED_DURATION;
     83 
     84     public static void initialize(Context context) {
     85         sDecelerateQuintInterpolator = AnimationUtils.loadInterpolator(context,
     86                 interpolator.decelerate_quint);
     87 
     88         final Point size = new Point();
     89         ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).
     90                 getDefaultDisplay().getSize(size);
     91         final int screenHeight = size.y;
     92 
     93         if (screenHeight >= ANIMATION_LONG_SCREEN_SIZE) {
     94             sAnimationDuration = ANIMATION_LONG_DURATION;
     95         } else if (screenHeight >= ANIMATION_MED_SCREEN_SIZE) {
     96             sAnimationDuration = ANIMATION_MED_DURATION;
     97         } else {
     98             sAnimationDuration = ANIMATION_SHORT_DURATION;
     99         }
    100     }
    101 
    102     public static int getDefaultAnimationDuration() {
    103         return sAnimationDuration;
    104     }
    105 
    106     public static Interpolator getDefaultAnimationInterpolator() {
    107         return sDecelerateQuintInterpolator;
    108     }
    109 
    110     /**
    111      * Add animations to translate a view's X-translation.  {@link AnimatorListener} can be null.
    112      */
    113     private static void addXTranslationAnimators(List<Animator> animators,
    114             final View view, int startTranslation, final int endTranslation, int animationDelay,
    115             AnimatorListener listener) {
    116         // We used to skip the animation if startTranslation == endTranslation,
    117         // but to add a recycle view listener, we need at least one animation
    118         view.setTranslationX(startTranslation);
    119         final ObjectAnimator translateAnimatorX = ObjectAnimator.ofFloat(view,
    120                 View.TRANSLATION_X, startTranslation, endTranslation);
    121         translateAnimatorX.setInterpolator(sDecelerateQuintInterpolator);
    122         translateAnimatorX.setDuration(sAnimationDuration);
    123         translateAnimatorX.setStartDelay(animationDelay);
    124         if (listener != null) {
    125             translateAnimatorX.addListener(listener);
    126         }
    127 
    128         animators.add(translateAnimatorX);
    129     }
    130 
    131     /**
    132      * Add animations to translate a view's Y-translation.  {@link AnimatorListener} can be null.
    133      */
    134     private static void addYTranslationAnimators(List<Animator> animators,
    135             final View view, int startTranslation, final int endTranslation, int animationDelay,
    136             AnimatorListener listener) {
    137         // We used to skip the animation if startTranslation == endTranslation,
    138         // but to add a recycle view listener, we need at least one animation
    139         view.setTranslationY(startTranslation);
    140         final ObjectAnimator translateAnimatorY = ObjectAnimator.ofFloat(view,
    141                 View.TRANSLATION_Y, startTranslation, endTranslation);
    142         translateAnimatorY.setInterpolator(sDecelerateQuintInterpolator);
    143         translateAnimatorY.setDuration(sAnimationDuration);
    144         translateAnimatorY.setStartDelay(animationDelay);
    145 
    146         if (listener != null) {
    147             translateAnimatorY.addListener(listener);
    148         }
    149 
    150         animators.add(translateAnimatorY);
    151     }
    152 
    153     /**
    154      * Translate a view to the specified translation values, and animate the translations to 0.
    155      */
    156     public static void addXYTranslationAnimators(List<Animator> animators, final View view,
    157             int xTranslation, int yTranslation, int animationDelay) {
    158         addXTranslationAnimators(animators, view, xTranslation, 0, animationDelay, null);
    159         addYTranslationAnimators(animators, view, yTranslation, 0, animationDelay, null);
    160     }
    161 
    162     /**
    163      * Translate a view to the specified translation values, while rotating to the specified
    164      * rotation value.
    165      */
    166     public static void addTranslationRotationAnimators(List<Animator> animators, final View view,
    167             int xTranslation, int yTranslation, float rotation, int animationDelay) {
    168         addXYTranslationAnimators(animators, view, xTranslation, yTranslation, animationDelay);
    169 
    170         view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    171         view.setRotation(rotation);
    172 
    173         final ObjectAnimator rotateAnimatorY = ObjectAnimator.ofFloat(view,
    174                 View.ROTATION, view.getRotation(), 0.0f);
    175         rotateAnimatorY.setInterpolator(sDecelerateQuintInterpolator);
    176         rotateAnimatorY.setDuration(sAnimationDuration);
    177         rotateAnimatorY.setStartDelay(animationDelay);
    178         rotateAnimatorY.addListener(new AnimatorListenerAdapter() {
    179             private boolean mIsCanceled = false;
    180 
    181             @Override
    182             public void onAnimationCancel(Animator animation) {
    183                 mIsCanceled = true;
    184             }
    185 
    186             @Override
    187             public void onAnimationEnd(Animator animation) {
    188                 if (!mIsCanceled) {
    189                     view.setRotation(0);
    190                 }
    191 
    192                 view.setLayerType(View.LAYER_TYPE_NONE, null);
    193             }
    194         });
    195 
    196         animators.add(rotateAnimatorY);
    197     }
    198 
    199     /**
    200      * Expand a view into view by scaling up vertically from 0.
    201      */
    202     public static void addExpandInAnimators(List<Animator> animators, final View view,
    203             int animationDelay) {
    204         view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    205         view.setScaleY(0);
    206 
    207         final ObjectAnimator scaleAnimatorY = ObjectAnimator.ofFloat(view,
    208                 View.SCALE_Y, view.getScaleY(), 1.0f);
    209         scaleAnimatorY.setInterpolator(sDecelerateQuintInterpolator);
    210         scaleAnimatorY.setDuration(sAnimationDuration);
    211         scaleAnimatorY.setStartDelay(animationDelay);
    212         scaleAnimatorY.addListener(new AnimatorListenerAdapter() {
    213             @Override
    214             public void onAnimationEnd(Animator animation) {
    215                 view.setScaleY(1.0f);
    216                 view.setLayerType(View.LAYER_TYPE_NONE, null);
    217             }
    218         });
    219 
    220         animators.add(scaleAnimatorY);
    221     }
    222 
    223     /**
    224      * Collapse a view out by scaling it from its current scaled value to 0.
    225      */
    226     public static void addCollapseOutAnimators(List<Animator> animators, final View view,
    227             int animationDelay) {
    228         view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    229 
    230         final ObjectAnimator scaleAnimatorY = ObjectAnimator.ofFloat(view, View.SCALE_Y,
    231                 view.getScaleY(), 0);
    232         scaleAnimatorY.setInterpolator(sDecelerateQuintInterpolator);
    233         scaleAnimatorY.setDuration(sAnimationDuration);
    234         scaleAnimatorY.setStartDelay(animationDelay);
    235         scaleAnimatorY.addListener(new AnimatorListenerAdapter() {
    236             @Override
    237             public void onAnimationEnd(Animator animation) {
    238                 view.setScaleY(0);
    239                 view.setLayerType(View.LAYER_TYPE_NONE, null);
    240             }
    241         });
    242 
    243         animators.add(scaleAnimatorY);
    244     }
    245 
    246     /**
    247      * Collapse a view out by scaling it from its current scaled value to 0.
    248      * The animators are expected to run immediately without a start delay.
    249      */
    250     public static void addCollapseOutAnimators(List<Animator> animators, final View view) {
    251         addCollapseOutAnimators(animators, view, 0 /* animation delay */);
    252     }
    253 
    254 
    255 
    256     /**
    257      * Fly a view out by moving it vertically off the bottom of the screen.
    258      */
    259     public static void addFlyOutAnimators(List<Animator> animators,
    260             final View view, int startTranslation, int endTranslation, int animationDelay) {
    261         addYTranslationAnimators(animators, view, startTranslation, endTranslation,
    262                 animationDelay, null);
    263     }
    264 
    265     public static void addFlyOutAnimators(List<Animator> animators, final View view,
    266             int startTranslation, int endTranslation) {
    267         addFlyOutAnimators(animators, view, startTranslation,
    268                 endTranslation, 0 /* animation delay */);
    269     }
    270 
    271     public static void addSlideInFromRightAnimators(List<Animator> animators, final View view,
    272             int startTranslation, int animationDelay) {
    273         addXTranslationAnimators(animators, view, startTranslation, 0, animationDelay, null);
    274         addFadeAnimators(animators, view, 0, 1.0f, animationDelay);
    275     }
    276 
    277     /**
    278      * Slide a view out of view from the start to end position, fading the view out as it
    279      * approaches the end position.
    280      */
    281     public static void addSlideOutAnimators(List<Animator> animators, final View view,
    282             int startTranslation, int endTranslation, int animationDelay) {
    283         addFadeAnimators(animators, view, view.getAlpha(), 0, animationDelay);
    284         addXTranslationAnimators(animators, view, startTranslation, endTranslation,
    285                 animationDelay, null);
    286     }
    287 
    288     /**
    289      * Slide a view out of view from the start to end position, fading the view out as it
    290      * approaches the end position.  The animators are expected to run immediately without a
    291      * start delay.
    292      */
    293     public static void addSlideOutAnimators(List<Animator> animators, final View view,
    294             int startTranslation, int endTranslation) {
    295         addSlideOutAnimators(animators, view, startTranslation,
    296                 endTranslation, 0 /* animation delay */);
    297     }
    298 
    299     /**
    300      * Add animations to fade a view from the specified start alpha value to end value.
    301      */
    302     public static void addFadeAnimators(List<Animator> animators, final View view,
    303             float startAlpha, final float endAlpha, int animationDelay) {
    304         if (startAlpha == endAlpha) {
    305             return;
    306         }
    307 
    308         view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    309         view.setAlpha(startAlpha);
    310 
    311         final ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(view, View.ALPHA,
    312                 view.getAlpha(), endAlpha);
    313         fadeAnimator.setInterpolator(sDecelerateQuintInterpolator);
    314         fadeAnimator.setDuration(sAnimationDuration);
    315         fadeAnimator.setStartDelay(animationDelay);
    316         fadeAnimator.addListener(new AnimatorListenerAdapter() {
    317             @Override
    318             public void onAnimationEnd(Animator animation) {
    319                 view.setAlpha(endAlpha);
    320                 view.setLayerType(View.LAYER_TYPE_NONE, null);
    321             }
    322         });
    323         animators.add(fadeAnimator);
    324     }
    325 
    326     /**
    327      * Add animations to fade a view from the specified start alpha value to end value.
    328      * The animators are expected to run immediately without a start delay.
    329      */
    330     public static void addFadeAnimators(List<Animator> animators, final View view,
    331             float startAlpha, final float endAlpha) {
    332         addFadeAnimators(animators, view, startAlpha, endAlpha, 0 /* animation delay */);
    333     }
    334 }
    335