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 import com.android.tv.common.R;
     31 
     32 /** A helper class for setup animation. */
     33 public final class SetupAnimationHelper {
     34     public static final long DELAY_BETWEEN_SIBLINGS_MS = applyAnimationTimeScale(33);
     35 
     36     private static final float ANIMATION_TIME_SCALE = 1.0f;
     37 
     38     private static boolean sInitialized;
     39     private static long sFragmentTransitionDuration;
     40     private static int sFragmentTransitionLongDistance;
     41     private static int sFragmentTransitionShortDistance;
     42 
     43     private SetupAnimationHelper() {}
     44 
     45     /** Load initial parameters. This method should be called before using this class. */
     46     public static void initialize(Context context) {
     47         if (sInitialized) {
     48             return;
     49         }
     50         sFragmentTransitionDuration =
     51                 context.getResources().getInteger(R.integer.setup_fragment_transition_duration);
     52         sFragmentTransitionLongDistance =
     53                 context.getResources()
     54                         .getDimensionPixelOffset(R.dimen.setup_fragment_transition_long_distance);
     55         sFragmentTransitionShortDistance =
     56                 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 final 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         /** Sets the duration of the transition. */
     89         public TransitionBuilder setDuration(long duration) {
     90             mDuration = duration;
     91             return this;
     92         }
     93 
     94         /**
     95          * Sets the ID of the view whose descendants will perform delayed move.
     96          *
     97          * @see android.view.ViewGroup#isTransitionGroup
     98          */
     99         public TransitionBuilder setParentIdsForDelay(int[] parentIdForDelay) {
    100             mParentIdForDelay = parentIdForDelay;
    101             return this;
    102         }
    103 
    104         /** Sets the ID's of the views which will not be included in the transition. */
    105         public TransitionBuilder setExcludeIds(int[] excludeIds) {
    106             mExcludeIds = excludeIds;
    107             return this;
    108         }
    109 
    110         /** Builds and returns the {@link android.transition.Transition}. */
    111         public Transition build() {
    112             FadeAndShortSlide transition = new FadeAndShortSlide(mSlideEdge, mParentIdForDelay);
    113             transition.setDistance(mDistance);
    114             transition.setDuration(mDuration);
    115             if (mExcludeIds != null) {
    116                 for (int id : mExcludeIds) {
    117                     transition.excludeTarget(id, true);
    118                 }
    119             }
    120             return transition;
    121         }
    122     }
    123 
    124     /** Changes the move distance of the {@code transition} to long distance. */
    125     public static void setLongDistance(FadeAndShortSlide transition) {
    126         checkInitialized();
    127         transition.setDistance(sFragmentTransitionLongDistance);
    128     }
    129 
    130     /** Changes the move distance of the {@code transition} to short distance. */
    131     public static void setShortDistance(FadeAndShortSlide transition) {
    132         checkInitialized();
    133         transition.setDistance(sFragmentTransitionShortDistance);
    134     }
    135 
    136     /** Applies the animation scale to the given {@code animator}. */
    137     public static Animator applyAnimationTimeScale(Animator animator) {
    138         if (animator instanceof AnimatorSet) {
    139             for (Animator child : ((AnimatorSet) animator).getChildAnimations()) {
    140                 applyAnimationTimeScale(child);
    141             }
    142         }
    143         if (animator.getDuration() > 0) {
    144             animator.setDuration((long) (animator.getDuration() * ANIMATION_TIME_SCALE));
    145         }
    146         animator.setStartDelay((long) (animator.getStartDelay() * ANIMATION_TIME_SCALE));
    147         return animator;
    148     }
    149 
    150     /** Applies the animation scale to the given {@code transition}. */
    151     public static Transition applyAnimationTimeScale(Transition transition) {
    152         if (transition instanceof TransitionSet) {
    153             TransitionSet set = (TransitionSet) transition;
    154             int count = set.getTransitionCount();
    155             for (int i = 0; i < count; ++i) {
    156                 applyAnimationTimeScale(set.getTransitionAt(i));
    157             }
    158         }
    159         if (transition.getDuration() > 0) {
    160             transition.setDuration((long) (transition.getDuration() * ANIMATION_TIME_SCALE));
    161         }
    162         transition.setStartDelay((long) (transition.getStartDelay() * ANIMATION_TIME_SCALE));
    163         return transition;
    164     }
    165 
    166     /** Applies the animation scale to the given {@code time}. */
    167     public static long applyAnimationTimeScale(long time) {
    168         return (long) (time * ANIMATION_TIME_SCALE);
    169     }
    170 
    171     /**
    172      * Returns an animator which animates the source image of the {@link ImageView}.
    173      *
    174      * <p>The frame rate is 60 fps.
    175      */
    176     public static ObjectAnimator createFrameAnimator(ImageView imageView, int[] frames) {
    177         return createFrameAnimatorWithDelay(imageView, frames, 0);
    178     }
    179 
    180     /**
    181      * Returns an animator which animates the source image of the {@link ImageView} with start
    182      * delay.
    183      *
    184      * <p>The frame rate is 60 fps.
    185      */
    186     public static ObjectAnimator createFrameAnimatorWithDelay(
    187             ImageView imageView, int[] frames, long startDelay) {
    188         ObjectAnimator animator = ObjectAnimator.ofInt(imageView, "imageResource", frames);
    189         // Make it 60 fps.
    190         animator.setDuration(frames.length * 1000 / 60);
    191         animator.setInterpolator(null);
    192         animator.setStartDelay(startDelay);
    193         animator.setEvaluator(
    194                 new TypeEvaluator<Integer>() {
    195                     @Override
    196                     public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
    197                         return startValue;
    198                     }
    199                 });
    200         return animator;
    201     }
    202 
    203     /**
    204      * Creates a fade out animator.
    205      *
    206      * @param view The view which will be animated.
    207      * @param duration The duration of the animation.
    208      * @param makeVisibleAfterAnimation If {@code true}, the view will become visible after the
    209      *     animation ends.
    210      */
    211     public static Animator createFadeOutAnimator(
    212             final View view, long duration, boolean makeVisibleAfterAnimation) {
    213         ObjectAnimator animator =
    214                 ObjectAnimator.ofFloat(view, View.ALPHA, 1.0f, 0.0f).setDuration(duration);
    215         if (makeVisibleAfterAnimation) {
    216             animator.addListener(
    217                     new AnimatorListenerAdapter() {
    218                         @Override
    219                         public void onAnimationEnd(Animator animation) {
    220                             view.setAlpha(1.0f);
    221                         }
    222                     });
    223         }
    224         return animator;
    225     }
    226 }
    227