Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.tv.common.ui.setup.animation;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.AnimatorSet;
     22 import android.animation.ObjectAnimator;
     23 import android.animation.TypeEvaluator;
     24 import android.content.Context;
     25 import android.transition.Transition;
     26 import android.transition.TransitionSet;
     27 import android.view.Gravity;
     28 import android.view.View;
     29 import android.widget.ImageView;
     30 
     31 import com.android.tv.common.R;
     32 
     33 /**
     34  * A helper class for setup animation.
     35  */
     36 public final class SetupAnimationHelper {
     37     public static final long DELAY_BETWEEN_SIBLINGS_MS = applyAnimationTimeScale(33);
     38 
     39     private static final float ANIMATION_TIME_SCALE = 1.0f;
     40 
     41     private static boolean sInitialized;
     42     private static long sFragmentTransitionDuration;
     43     private static int sFragmentTransitionLongDistance;
     44     private static int sFragmentTransitionShortDistance;
     45 
     46     private SetupAnimationHelper() { }
     47 
     48     /**
     49      * Load initial parameters. This method should be called before using this class.
     50      */
     51     public static void initialize(Context context) {
     52         sFragmentTransitionDuration = context.getResources()
     53                 .getInteger(R.integer.setup_fragment_transition_duration);
     54         sFragmentTransitionLongDistance = context.getResources()
     55                 .getDimensionPixelOffset(R.dimen.setup_fragment_transition_long_distance);
     56         sFragmentTransitionShortDistance = context.getResources()
     57                 .getDimensionPixelOffset(R.dimen.setup_fragment_transition_short_distance);
     58         sInitialized = true;
     59     }
     60 
     61     private static void checkInitialized() {
     62         if (!sInitialized) {
     63             throw new IllegalStateException("SetupAnimationHelper not initialized");
     64         }
     65     }
     66 
     67     public static class TransitionBuilder {
     68         private int mSlideEdge = Gravity.START;
     69         private int mDistance = sFragmentTransitionLongDistance;
     70         private long mDuration = sFragmentTransitionDuration;
     71         private int[] mParentIdForDelay;
     72         private int[] mExcludeIds;
     73 
     74         public TransitionBuilder() {
     75             checkInitialized();
     76         }
     77 
     78         /**
     79          * Sets the edge of the slide transition.
     80          *
     81          * @see android.transition.Slide#setSlideEdge
     82          */
     83         public TransitionBuilder setSlideEdge(int slideEdge) {
     84             mSlideEdge = slideEdge;
     85             return this;
     86         }
     87 
     88         /**
     89          * Sets the duration of the transition.
     90          */
     91         public TransitionBuilder setDuration(long duration) {
     92             mDuration = duration;
     93             return this;
     94         }
     95 
     96         /**
     97          * Sets the ID of the view whose descendants will perform delayed move.
     98          *
     99          * @see android.view.ViewGroup#isTransitionGroup
    100          */
    101         public TransitionBuilder setParentIdsForDelay(int[] parentIdForDelay) {
    102             mParentIdForDelay = parentIdForDelay;
    103             return this;
    104         }
    105 
    106         /**
    107          * Sets the ID's of the views which will not be included in the transition.
    108          */
    109         public TransitionBuilder setExcludeIds(int[] excludeIds) {
    110             mExcludeIds = excludeIds;
    111             return this;
    112         }
    113 
    114         /**
    115          * Builds and returns the {@link android.transition.Transition}.
    116          */
    117         public Transition build() {
    118             FadeAndShortSlide transition = new FadeAndShortSlide(mSlideEdge, mParentIdForDelay);
    119             transition.setDistance(mDistance);
    120             transition.setDuration(mDuration);
    121             if (mExcludeIds != null) {
    122                 for (int id : mExcludeIds) {
    123                     transition.excludeTarget(id, true);
    124                 }
    125             }
    126             return transition;
    127         }
    128     }
    129 
    130     /**
    131      * Changes the move distance of the {@code transition} to long distance.
    132      */
    133     public static void setLongDistance(FadeAndShortSlide transition) {
    134         checkInitialized();
    135         transition.setDistance(sFragmentTransitionLongDistance);
    136     }
    137 
    138     /**
    139      * Changes the move distance of the {@code transition} to short distance.
    140      */
    141     public static void setShortDistance(FadeAndShortSlide transition) {
    142         checkInitialized();
    143         transition.setDistance(sFragmentTransitionShortDistance);
    144     }
    145 
    146     /**
    147      * Applies the animation scale to the given {@code animator}.
    148      */
    149     public static Animator applyAnimationTimeScale(Animator animator) {
    150         if (animator instanceof AnimatorSet) {
    151             for (Animator child : ((AnimatorSet) animator).getChildAnimations()) {
    152                 applyAnimationTimeScale(child);
    153             }
    154         }
    155         if (animator.getDuration() > 0) {
    156             animator.setDuration((long) (animator.getDuration() * ANIMATION_TIME_SCALE));
    157         }
    158         animator.setStartDelay((long) (animator.getStartDelay() * ANIMATION_TIME_SCALE));
    159         return animator;
    160     }
    161 
    162     /**
    163      * Applies the animation scale to the given {@code transition}.
    164      */
    165     public static Transition applyAnimationTimeScale(Transition transition) {
    166         if (transition instanceof TransitionSet) {
    167             TransitionSet set = (TransitionSet) transition;
    168             int count = set.getTransitionCount();
    169             for (int i = 0; i < count; ++i) {
    170                 applyAnimationTimeScale(set.getTransitionAt(i));
    171             }
    172         }
    173         if (transition.getDuration() > 0) {
    174             transition.setDuration((long) (transition.getDuration() * ANIMATION_TIME_SCALE));
    175         }
    176         transition.setStartDelay((long) (transition.getStartDelay() * ANIMATION_TIME_SCALE));
    177         return transition;
    178     }
    179 
    180     /**
    181      * Applies the animation scale to the given {@code time}.
    182      */
    183     public static long applyAnimationTimeScale(long time) {
    184         return (long) (time * ANIMATION_TIME_SCALE);
    185     }
    186 
    187     /**
    188      * Returns an animator which animates the source image of the {@link ImageView}.
    189      *
    190      * <p>The frame rate is 60 fps.
    191      */
    192     public static ObjectAnimator createFrameAnimator(ImageView imageView, int[] frames) {
    193         return createFrameAnimatorWithDelay(imageView, frames, 0);
    194     }
    195 
    196     /**
    197      * Returns an animator which animates the source image of the {@link ImageView} with start delay.
    198      *
    199      * <p>The frame rate is 60 fps.
    200      */
    201     public static ObjectAnimator createFrameAnimatorWithDelay(ImageView imageView, int[] frames,
    202             long startDelay) {
    203         ObjectAnimator animator = ObjectAnimator.ofInt(imageView, "imageResource", frames);
    204         // Make it 60 fps.
    205         animator.setDuration(frames.length * 1000 / 60);
    206         animator.setInterpolator(null);
    207         animator.setStartDelay(startDelay);
    208         animator.setEvaluator(new TypeEvaluator<Integer>() {
    209             @Override
    210             public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
    211                 return startValue;
    212             }
    213         });
    214         return animator;
    215     }
    216 
    217     /**
    218      * Creates a fade out animator.
    219      *
    220      * @param view The view which will be animated.
    221      * @param duration The duration of the animation.
    222      * @param makeVisibleAfterAnimation If {@code true}, the view will become visible after the
    223      * animation ends.
    224      */
    225     public static Animator createFadeOutAnimator(final View view, long duration,
    226             boolean makeVisibleAfterAnimation) {
    227         ObjectAnimator animator =
    228                 ObjectAnimator.ofFloat(view, View.ALPHA, 1.0f, 0.0f).setDuration(duration);
    229         if (makeVisibleAfterAnimation) {
    230             animator.addListener(new AnimatorListenerAdapter() {
    231                 @Override
    232                 public void onAnimationEnd(Animator animation) {
    233                     view.setAlpha(1.0f);
    234                 }
    235             });
    236         }
    237         return animator;
    238     }
    239 }
    240