Advertisement
Guest User

ViewPropertyAnimator

a guest
Jan 14th, 2013
258
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 44.54 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2011 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 android.view;
  18.  
  19. import android.animation.Animator;
  20. import android.animation.ValueAnimator;
  21. import android.animation.TimeInterpolator;
  22.  
  23. import java.util.ArrayList;
  24. import java.util.HashMap;
  25. import java.util.Set;
  26.  
  27. /**
  28.  * This class enables automatic and optimized animation of select properties on View objects.
  29.  * If only one or two properties on a View object are being animated, then using an
  30.  * {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
  31.  * are well equipped to do the right thing to set the property and invalidate the view
  32.  * appropriately. But if several properties are animated simultaneously, or if you just want a
  33.  * more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
  34.  * more well-suited to the task.
  35.  *
  36.  * <p>This class may provide better performance for several simultaneous animations, because
  37.  * it will optimize invalidate calls to take place only once for several properties instead of each
  38.  * animated property independently causing its own invalidation. Also, the syntax of using this
  39.  * class could be easier to use because the caller need only tell the View object which
  40.  * property to animate, and the value to animate either to or by, and this class handles the
  41.  * details of configuring the underlying Animator class and starting it.</p>
  42.  *
  43.  * <p>This class is not constructed by the caller, but rather by the View whose properties
  44.  * it will animate. Calls to {@link android.view.View#animate()} will return a reference
  45.  * to the appropriate ViewPropertyAnimator object for that View.</p>
  46.  *
  47.  */
  48. public class ViewPropertyAnimator {
  49.  
  50.     /**
  51.      * The View whose properties are being animated by this class. This is set at
  52.      * construction time.
  53.      */
  54.     private final View mView;
  55.  
  56.     /**
  57.      * The duration of the underlying Animator object. By default, we don't set the duration
  58.      * on the Animator and just use its default duration. If the duration is ever set on this
  59.      * Animator, then we use the duration that it was set to.
  60.      */
  61.     private long mDuration;
  62.  
  63.     /**
  64.      * A flag indicating whether the duration has been set on this object. If not, we don't set
  65.      * the duration on the underlying Animator, but instead just use its default duration.
  66.      */
  67.     private boolean mDurationSet = false;
  68.  
  69.     /**
  70.      * The startDelay of the underlying Animator object. By default, we don't set the startDelay
  71.      * on the Animator and just use its default startDelay. If the startDelay is ever set on this
  72.      * Animator, then we use the startDelay that it was set to.
  73.      */
  74.     private long mStartDelay = 0;
  75.  
  76.     /**
  77.      * A flag indicating whether the startDelay has been set on this object. If not, we don't set
  78.      * the startDelay on the underlying Animator, but instead just use its default startDelay.
  79.      */
  80.     private boolean mStartDelaySet = false;
  81.  
  82.     /**
  83.      * The interpolator of the underlying Animator object. By default, we don't set the interpolator
  84.      * on the Animator and just use its default interpolator. If the interpolator is ever set on
  85.      * this Animator, then we use the interpolator that it was set to.
  86.      */
  87.     private TimeInterpolator mInterpolator;
  88.  
  89.     /**
  90.      * A flag indicating whether the interpolator has been set on this object. If not, we don't set
  91.      * the interpolator on the underlying Animator, but instead just use its default interpolator.
  92.      */
  93.     private boolean mInterpolatorSet = false;
  94.  
  95.     /**
  96.      * Listener for the lifecycle events of the underlying
  97.      */
  98.     private Animator.AnimatorListener mListener = null;
  99.  
  100.     /**
  101.      * This listener is the mechanism by which the underlying Animator causes changes to the
  102.      * properties currently being animated, as well as the cleanup after an animation is
  103.      * complete.
  104.      */
  105.     private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
  106.  
  107.     /**
  108.      * This list holds the properties that have been asked to animate. We allow the caller to
  109.      * request several animations prior to actually starting the underlying animator. This
  110.      * enables us to run one single animator to handle several properties in parallel. Each
  111.      * property is tossed onto the pending list until the animation actually starts (which is
  112.      * done by posting it onto mView), at which time the pending list is cleared and the properties
  113.      * on that list are added to the list of properties associated with that animator.
  114.      */
  115.     ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
  116.     private Runnable mPendingSetupAction;
  117.     private Runnable mPendingCleanupAction;
  118.     private Runnable mPendingOnStartAction;
  119.     private Runnable mPendingOnEndAction;
  120.  
  121.     /**
  122.      * Constants used to associate a property being requested and the mechanism used to set
  123.      * the property (this class calls directly into View to set the properties in question).
  124.      */
  125.     private static final int NONE           = 0x0000;
  126.     private static final int TRANSLATION_X  = 0x0001;
  127.     private static final int TRANSLATION_Y  = 0x0002;
  128.     private static final int SCALE_X        = 0x0004;
  129.     private static final int SCALE_Y        = 0x0008;
  130.     private static final int ROTATION       = 0x0010;
  131.     private static final int ROTATION_X     = 0x0020;
  132.     private static final int ROTATION_Y     = 0x0040;
  133.     private static final int X              = 0x0080;
  134.     private static final int Y              = 0x0100;
  135.     private static final int ALPHA          = 0x0200;
  136.  
  137.     private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
  138.             ROTATION | ROTATION_X | ROTATION_Y | X | Y;
  139.  
  140.     /**
  141.      * The mechanism by which the user can request several properties that are then animated
  142.      * together works by posting this Runnable to start the underlying Animator. Every time
  143.      * a property animation is requested, we cancel any previous postings of the Runnable
  144.      * and re-post it. This means that we will only ever run the Runnable (and thus start the
  145.      * underlying animator) after the caller is done setting the properties that should be
  146.      * animated together.
  147.      */
  148.     private Runnable mAnimationStarter = new Runnable() {
  149.         @Override
  150.         public void run() {
  151.             startAnimation();
  152.         }
  153.     };
  154.  
  155.     /**
  156.      * This class holds information about the overall animation being run on the set of
  157.      * properties. The mask describes which properties are being animated and the
  158.      * values holder is the list of all property/value objects.
  159.      */
  160.     private static class PropertyBundle {
  161.         int mPropertyMask;
  162.         ArrayList<NameValuesHolder> mNameValuesHolder;
  163.  
  164.         PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
  165.             mPropertyMask = propertyMask;
  166.             mNameValuesHolder = nameValuesHolder;
  167.         }
  168.  
  169.         /**
  170.          * Removes the given property from being animated as a part of this
  171.          * PropertyBundle. If the property was a part of this bundle, it returns
  172.          * true to indicate that it was, in fact, canceled. This is an indication
  173.          * to the caller that a cancellation actually occurred.
  174.          *
  175.          * @param propertyConstant The property whose cancellation is requested.
  176.          * @return true if the given property is a part of this bundle and if it
  177.          * has therefore been canceled.
  178.          */
  179.         boolean cancel(int propertyConstant) {
  180.             if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
  181.                 int count = mNameValuesHolder.size();
  182.                 for (int i = 0; i < count; ++i) {
  183.                     NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
  184.                     if (nameValuesHolder.mNameConstant == propertyConstant) {
  185.                         mNameValuesHolder.remove(i);
  186.                         mPropertyMask &= ~propertyConstant;
  187.                         return true;
  188.                     }
  189.                 }
  190.             }
  191.             return false;
  192.         }
  193.     }
  194.  
  195.     /**
  196.      * This list tracks the list of properties being animated by any particular animator.
  197.      * In most situations, there would only ever be one animator running at a time. But it is
  198.      * possible to request some properties to animate together, then while those properties
  199.      * are animating, to request some other properties to animate together. The way that
  200.      * works is by having this map associate the group of properties being animated with the
  201.      * animator handling the animation. On every update event for an Animator, we ask the
  202.      * map for the associated properties and set them accordingly.
  203.      */
  204.     private HashMap<Animator, PropertyBundle> mAnimatorMap =
  205.             new HashMap<Animator, PropertyBundle>();
  206.     private HashMap<Animator, Runnable> mAnimatorSetupMap;
  207.     private HashMap<Animator, Runnable> mAnimatorCleanupMap;
  208.     private HashMap<Animator, Runnable> mAnimatorOnStartMap;
  209.     private HashMap<Animator, Runnable> mAnimatorOnEndMap;
  210.  
  211.     /**
  212.      * This is the information we need to set each property during the animation.
  213.      * mNameConstant is used to set the appropriate field in View, and the from/delta
  214.      * values are used to calculate the animated value for a given animation fraction
  215.      * during the animation.
  216.      */
  217.     private static class NameValuesHolder {
  218.         int mNameConstant;
  219.         float mFromValue;
  220.         float mDeltaValue;
  221.         NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
  222.             mNameConstant = nameConstant;
  223.             mFromValue = fromValue;
  224.             mDeltaValue = deltaValue;
  225.         }
  226.     }
  227.  
  228.     /**
  229.      * Constructor, called by View. This is private by design, as the user should only
  230.      * get a ViewPropertyAnimator by calling View.animate().
  231.      *
  232.      * @param view The View associated with this ViewPropertyAnimator
  233.      */
  234.     ViewPropertyAnimator(View view) {
  235.         mView = view;
  236.         view.ensureTransformationInfo();
  237.     }
  238.  
  239.     /**
  240.      * Sets the duration for the underlying animator that animates the requested properties.
  241.      * By default, the animator uses the default value for ValueAnimator. Calling this method
  242.      * will cause the declared value to be used instead.
  243.      * @param duration The length of ensuing property animations, in milliseconds. The value
  244.      * cannot be negative.
  245.      * @return This object, allowing calls to methods in this class to be chained.
  246.      */
  247.     public ViewPropertyAnimator setDuration(long duration) {
  248.         if (duration < 0) {
  249.             throw new IllegalArgumentException("Animators cannot have negative duration: " +
  250.                     duration);
  251.         }
  252.         mDurationSet = true;
  253.         mDuration = duration;
  254.         return this;
  255.     }
  256.  
  257.     /**
  258.      * Returns the current duration of property animations. If the duration was set on this
  259.      * object, that value is returned. Otherwise, the default value of the underlying Animator
  260.      * is returned.
  261.      *
  262.      * @see #setDuration(long)
  263.      * @return The duration of animations, in milliseconds.
  264.      */
  265.     public long getDuration() {
  266.         if (mDurationSet) {
  267.             return mDuration;
  268.         } else {
  269.             // Just return the default from ValueAnimator, since that's what we'd get if
  270.             // the value has not been set otherwise
  271.             return new ValueAnimator().getDuration();
  272.         }
  273.     }
  274.  
  275.     /**
  276.      * Returns the current startDelay of property animations. If the startDelay was set on this
  277.      * object, that value is returned. Otherwise, the default value of the underlying Animator
  278.      * is returned.
  279.      *
  280.      * @see #setStartDelay(long)
  281.      * @return The startDelay of animations, in milliseconds.
  282.      */
  283.     public long getStartDelay() {
  284.         if (mStartDelaySet) {
  285.             return mStartDelay;
  286.         } else {
  287.             // Just return the default from ValueAnimator (0), since that's what we'd get if
  288.             // the value has not been set otherwise
  289.             return 0;
  290.         }
  291.     }
  292.  
  293.     /**
  294.      * Sets the startDelay for the underlying animator that animates the requested properties.
  295.      * By default, the animator uses the default value for ValueAnimator. Calling this method
  296.      * will cause the declared value to be used instead.
  297.      * @param startDelay The delay of ensuing property animations, in milliseconds. The value
  298.      * cannot be negative.
  299.      * @return This object, allowing calls to methods in this class to be chained.
  300.      */
  301.     public ViewPropertyAnimator setStartDelay(long startDelay) {
  302.         if (startDelay < 0) {
  303.             throw new IllegalArgumentException("Animators cannot have negative duration: " +
  304.                     startDelay);
  305.         }
  306.         mStartDelaySet = true;
  307.         mStartDelay = startDelay;
  308.         return this;
  309.     }
  310.  
  311.     /**
  312.      * Sets the interpolator for the underlying animator that animates the requested properties.
  313.      * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
  314.      * will cause the declared object to be used instead.
  315.      *
  316.      * @param interpolator The TimeInterpolator to be used for ensuing property animations.
  317.      * @return This object, allowing calls to methods in this class to be chained.
  318.      */
  319.     public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
  320.         mInterpolatorSet = true;
  321.         mInterpolator = interpolator;
  322.         return this;
  323.     }
  324.  
  325.     /**
  326.      * Sets a listener for events in the underlying Animators that run the property
  327.      * animations.
  328.      *
  329.      * @param listener The listener to be called with AnimatorListener events.
  330.      * @return This object, allowing calls to methods in this class to be chained.
  331.      */
  332.     public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
  333.         mListener = listener;
  334.         return this;
  335.     }
  336.  
  337.     /**
  338.      * Starts the currently pending property animations immediately. Calling <code>start()</code>
  339.      * is optional because all animations start automatically at the next opportunity. However,
  340.      * if the animations are needed to start immediately and synchronously (not at the time when
  341.      * the next event is processed by the hierarchy, which is when the animations would begin
  342.      * otherwise), then this method can be used.
  343.      */
  344.     public void start() {
  345.         mView.removeCallbacks(mAnimationStarter);
  346.         startAnimation();
  347.     }
  348.  
  349.     /**
  350.      * Cancels all property animations that are currently running or pending.
  351.      */
  352.     public void cancel() {
  353.         if (mAnimatorMap.size() > 0) {
  354.             HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
  355.                     (HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
  356.             Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
  357.             for (Animator runningAnim : animatorSet) {
  358.                 runningAnim.cancel();
  359.             }
  360.         }
  361.         mPendingAnimations.clear();
  362.         mView.removeCallbacks(mAnimationStarter);
  363.     }
  364.  
  365.     /**
  366.      * This method will cause the View's <code>x</code> property to be animated to the
  367.      * specified value. Animations already running on the property will be canceled.
  368.      *
  369.      * @param value The value to be animated to.
  370.      * @see View#setX(float)
  371.      * @return This object, allowing calls to methods in this class to be chained.
  372.      */
  373.     public ViewPropertyAnimator x(float value) {
  374.         animateProperty(X, value);
  375.         return this;
  376.     }
  377.  
  378.     /**
  379.      * This method will cause the View's <code>x</code> property to be animated by the
  380.      * specified value. Animations already running on the property will be canceled.
  381.      *
  382.      * @param value The amount to be animated by, as an offset from the current value.
  383.      * @see View#setX(float)
  384.      * @return This object, allowing calls to methods in this class to be chained.
  385.      */
  386.     public ViewPropertyAnimator xBy(float value) {
  387.         animatePropertyBy(X, value);
  388.         return this;
  389.     }
  390.  
  391.     /**
  392.      * This method will cause the View's <code>y</code> property to be animated to the
  393.      * specified value. Animations already running on the property will be canceled.
  394.      *
  395.      * @param value The value to be animated to.
  396.      * @see View#setY(float)
  397.      * @return This object, allowing calls to methods in this class to be chained.
  398.      */
  399.     public ViewPropertyAnimator y(float value) {
  400.         animateProperty(Y, value);
  401.         return this;
  402.     }
  403.  
  404.     /**
  405.      * This method will cause the View's <code>y</code> property to be animated by the
  406.      * specified value. Animations already running on the property will be canceled.
  407.      *
  408.      * @param value The amount to be animated by, as an offset from the current value.
  409.      * @see View#setY(float)
  410.      * @return This object, allowing calls to methods in this class to be chained.
  411.      */
  412.     public ViewPropertyAnimator yBy(float value) {
  413.         animatePropertyBy(Y, value);
  414.         return this;
  415.     }
  416.  
  417.     /**
  418.      * This method will cause the View's <code>rotation</code> property to be animated to the
  419.      * specified value. Animations already running on the property will be canceled.
  420.      *
  421.      * @param value The value to be animated to.
  422.      * @see View#setRotation(float)
  423.      * @return This object, allowing calls to methods in this class to be chained.
  424.      */
  425.     public ViewPropertyAnimator rotation(float value) {
  426.         animateProperty(ROTATION, value);
  427.         return this;
  428.     }
  429.  
  430.     /**
  431.      * This method will cause the View's <code>rotation</code> property to be animated by the
  432.      * specified value. Animations already running on the property will be canceled.
  433.      *
  434.      * @param value The amount to be animated by, as an offset from the current value.
  435.      * @see View#setRotation(float)
  436.      * @return This object, allowing calls to methods in this class to be chained.
  437.      */
  438.     public ViewPropertyAnimator rotationBy(float value) {
  439.         animatePropertyBy(ROTATION, value);
  440.         return this;
  441.     }
  442.  
  443.     /**
  444.      * This method will cause the View's <code>rotationX</code> property to be animated to the
  445.      * specified value. Animations already running on the property will be canceled.
  446.      *
  447.      * @param value The value to be animated to.
  448.      * @see View#setRotationX(float)
  449.      * @return This object, allowing calls to methods in this class to be chained.
  450.      */
  451.     public ViewPropertyAnimator rotationX(float value) {
  452.         animateProperty(ROTATION_X, value);
  453.         return this;
  454.     }
  455.  
  456.     /**
  457.      * This method will cause the View's <code>rotationX</code> property to be animated by the
  458.      * specified value. Animations already running on the property will be canceled.
  459.      *
  460.      * @param value The amount to be animated by, as an offset from the current value.
  461.      * @see View#setRotationX(float)
  462.      * @return This object, allowing calls to methods in this class to be chained.
  463.      */
  464.     public ViewPropertyAnimator rotationXBy(float value) {
  465.         animatePropertyBy(ROTATION_X, value);
  466.         return this;
  467.     }
  468.  
  469.     /**
  470.      * This method will cause the View's <code>rotationY</code> property to be animated to the
  471.      * specified value. Animations already running on the property will be canceled.
  472.      *
  473.      * @param value The value to be animated to.
  474.      * @see View#setRotationY(float)
  475.      * @return This object, allowing calls to methods in this class to be chained.
  476.      */
  477.     public ViewPropertyAnimator rotationY(float value) {
  478.         animateProperty(ROTATION_Y, value);
  479.         return this;
  480.     }
  481.  
  482.     /**
  483.      * This method will cause the View's <code>rotationY</code> property to be animated by the
  484.      * specified value. Animations already running on the property will be canceled.
  485.      *
  486.      * @param value The amount to be animated by, as an offset from the current value.
  487.      * @see View#setRotationY(float)
  488.      * @return This object, allowing calls to methods in this class to be chained.
  489.      */
  490.     public ViewPropertyAnimator rotationYBy(float value) {
  491.         animatePropertyBy(ROTATION_Y, value);
  492.         return this;
  493.     }
  494.  
  495.     /**
  496.      * This method will cause the View's <code>translationX</code> property to be animated to the
  497.      * specified value. Animations already running on the property will be canceled.
  498.      *
  499.      * @param value The value to be animated to.
  500.      * @see View#setTranslationX(float)
  501.      * @return This object, allowing calls to methods in this class to be chained.
  502.      */
  503.     public ViewPropertyAnimator translationX(float value) {
  504.         animateProperty(TRANSLATION_X, value);
  505.         return this;
  506.     }
  507.  
  508.     /**
  509.      * This method will cause the View's <code>translationX</code> property to be animated by the
  510.      * specified value. Animations already running on the property will be canceled.
  511.      *
  512.      * @param value The amount to be animated by, as an offset from the current value.
  513.      * @see View#setTranslationX(float)
  514.      * @return This object, allowing calls to methods in this class to be chained.
  515.      */
  516.     public ViewPropertyAnimator translationXBy(float value) {
  517.         animatePropertyBy(TRANSLATION_X, value);
  518.         return this;
  519.     }
  520.  
  521.     /**
  522.      * This method will cause the View's <code>translationY</code> property to be animated to the
  523.      * specified value. Animations already running on the property will be canceled.
  524.      *
  525.      * @param value The value to be animated to.
  526.      * @see View#setTranslationY(float)
  527.      * @return This object, allowing calls to methods in this class to be chained.
  528.      */
  529.     public ViewPropertyAnimator translationY(float value) {
  530.         animateProperty(TRANSLATION_Y, value);
  531.         return this;
  532.     }
  533.  
  534.     /**
  535.      * This method will cause the View's <code>translationY</code> property to be animated by the
  536.      * specified value. Animations already running on the property will be canceled.
  537.      *
  538.      * @param value The amount to be animated by, as an offset from the current value.
  539.      * @see View#setTranslationY(float)
  540.      * @return This object, allowing calls to methods in this class to be chained.
  541.      */
  542.     public ViewPropertyAnimator translationYBy(float value) {
  543.         animatePropertyBy(TRANSLATION_Y, value);
  544.         return this;
  545.     }
  546.  
  547.     /**
  548.      * This method will cause the View's <code>scaleX</code> property to be animated to the
  549.      * specified value. Animations already running on the property will be canceled.
  550.      *
  551.      * @param value The value to be animated to.
  552.      * @see View#setScaleX(float)
  553.      * @return This object, allowing calls to methods in this class to be chained.
  554.      */
  555.     public ViewPropertyAnimator scaleX(float value) {
  556.         animateProperty(SCALE_X, value);
  557.         return this;
  558.     }
  559.  
  560.     /**
  561.      * This method will cause the View's <code>scaleX</code> property to be animated by the
  562.      * specified value. Animations already running on the property will be canceled.
  563.      *
  564.      * @param value The amount to be animated by, as an offset from the current value.
  565.      * @see View#setScaleX(float)
  566.      * @return This object, allowing calls to methods in this class to be chained.
  567.      */
  568.     public ViewPropertyAnimator scaleXBy(float value) {
  569.         animatePropertyBy(SCALE_X, value);
  570.         return this;
  571.     }
  572.  
  573.     /**
  574.      * This method will cause the View's <code>scaleY</code> property to be animated to the
  575.      * specified value. Animations already running on the property will be canceled.
  576.      *
  577.      * @param value The value to be animated to.
  578.      * @see View#setScaleY(float)
  579.      * @return This object, allowing calls to methods in this class to be chained.
  580.      */
  581.     public ViewPropertyAnimator scaleY(float value) {
  582.         animateProperty(SCALE_Y, value);
  583.         return this;
  584.     }
  585.  
  586.     /**
  587.      * This method will cause the View's <code>scaleY</code> property to be animated by the
  588.      * specified value. Animations already running on the property will be canceled.
  589.      *
  590.      * @param value The amount to be animated by, as an offset from the current value.
  591.      * @see View#setScaleY(float)
  592.      * @return This object, allowing calls to methods in this class to be chained.
  593.      */
  594.     public ViewPropertyAnimator scaleYBy(float value) {
  595.         animatePropertyBy(SCALE_Y, value);
  596.         return this;
  597.     }
  598.  
  599.     /**
  600.      * This method will cause the View's <code>alpha</code> property to be animated to the
  601.      * specified value. Animations already running on the property will be canceled.
  602.      *
  603.      * @param value The value to be animated to.
  604.      * @see View#setAlpha(float)
  605.      * @return This object, allowing calls to methods in this class to be chained.
  606.      */
  607.     public ViewPropertyAnimator alpha(float value) {
  608.         animateProperty(ALPHA, value);
  609.         return this;
  610.     }
  611.  
  612.     /**
  613.      * This method will cause the View's <code>alpha</code> property to be animated by the
  614.      * specified value. Animations already running on the property will be canceled.
  615.      *
  616.      * @param value The amount to be animated by, as an offset from the current value.
  617.      * @see View#setAlpha(float)
  618.      * @return This object, allowing calls to methods in this class to be chained.
  619.      */
  620.     public ViewPropertyAnimator alphaBy(float value) {
  621.         animatePropertyBy(ALPHA, value);
  622.         return this;
  623.     }
  624.  
  625.     /**
  626.      * The View associated with this ViewPropertyAnimator will have its
  627.      * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
  628.      * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
  629.      * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
  630.      * the actual type of layer used internally depends on the runtime situation of the
  631.      * view. If the activity and this view are hardware-accelerated, then the layer will be
  632.      * accelerated as well. If the activity or the view is not accelerated, then the layer will
  633.      * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
  634.      *
  635.      * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
  636.      * layer type of the View will be restored when the animation ends to what it was when this
  637.      * method was called, and this setting on ViewPropertyAnimator is only valid for the next
  638.      * animation. Note that calling this method and then independently setting the layer type of
  639.      * the View (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will
  640.      * result in some inconsistency, including having the layer type restored to its pre-withLayer()
  641.      * value when the animation ends.</p>
  642.      *
  643.      * @see View#setLayerType(int, android.graphics.Paint)
  644.      * @return This object, allowing calls to methods in this class to be chained.
  645.      */
  646.     public ViewPropertyAnimator withLayer() {
  647.          mPendingSetupAction= new Runnable() {
  648.             @Override
  649.             public void run() {
  650.                 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
  651.             }
  652.         };
  653.         final int currentLayerType = mView.getLayerType();
  654.         mPendingCleanupAction = new Runnable() {
  655.             @Override
  656.             public void run() {
  657.                 mView.setLayerType(currentLayerType, null);
  658.             }
  659.         };
  660.         if (mAnimatorSetupMap == null) {
  661.             mAnimatorSetupMap = new HashMap<Animator, Runnable>();
  662.         }
  663.         if (mAnimatorCleanupMap == null) {
  664.             mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
  665.         }
  666.  
  667.         return this;
  668.     }
  669.  
  670.     /**
  671.      * Specifies an action to take place when the next animation runs. If there is a
  672.      * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
  673.      * action will run after that startDelay expires, when the actual animation begins.
  674.      * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
  675.      * choreographing ViewPropertyAnimator animations with other animations or actions
  676.      * in the application.
  677.      *
  678.      * @param runnable The action to run when the next animation starts.
  679.      * @return This object, allowing calls to methods in this class to be chained.
  680.      */
  681.     public ViewPropertyAnimator withStartAction(Runnable runnable) {
  682.         mPendingOnStartAction = runnable;
  683.         if (runnable != null && mAnimatorOnStartMap == null) {
  684.             mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
  685.         }
  686.         return this;
  687.     }
  688.  
  689.     /**
  690.      * Specifies an action to take place when the next animation ends. The action is only
  691.      * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
  692.      * that animation, the runnable will not run.
  693.      * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
  694.      * choreographing ViewPropertyAnimator animations with other animations or actions
  695.      * in the application.
  696.      *
  697.      * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
  698.      * <pre>
  699.      *     Runnable endAction = new Runnable() {
  700.      *         public void run() {
  701.      *             view.animate().x(0);
  702.      *         }
  703.      *     };
  704.      *     view.animate().x(200).onEnd(endAction);
  705.      * </pre>
  706.      *
  707.      * @param runnable The action to run when the next animation ends.
  708.      * @return This object, allowing calls to methods in this class to be chained.
  709.      */
  710.     public ViewPropertyAnimator withEndAction(Runnable runnable) {
  711.         mPendingOnEndAction = runnable;
  712.         if (runnable != null && mAnimatorOnEndMap == null) {
  713.             mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
  714.         }
  715.         return this;
  716.     }
  717.  
  718.     /**
  719.      * Starts the underlying Animator for a set of properties. We use a single animator that
  720.      * simply runs from 0 to 1, and then use that fractional value to set each property
  721.      * value accordingly.
  722.      */
  723.     private void startAnimation() {
  724.         mView.setHasTransientState(true);
  725.         ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
  726.         ArrayList<NameValuesHolder> nameValueList =
  727.                 (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
  728.         mPendingAnimations.clear();
  729.         int propertyMask = 0;
  730.         int propertyCount = nameValueList.size();
  731.         for (int i = 0; i < propertyCount; ++i) {
  732.             NameValuesHolder nameValuesHolder = nameValueList.get(i);
  733.             propertyMask |= nameValuesHolder.mNameConstant;
  734.         }
  735.         mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
  736.         if (mPendingSetupAction != null) {
  737.             mAnimatorSetupMap.put(animator, mPendingSetupAction);
  738.             mPendingSetupAction = null;
  739.         }
  740.         if (mPendingCleanupAction != null) {
  741.             mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
  742.             mPendingCleanupAction = null;
  743.         }
  744.         if (mPendingOnStartAction != null) {
  745.             mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
  746.             mPendingOnStartAction = null;
  747.         }
  748.         if (mPendingOnEndAction != null) {
  749.             mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
  750.             mPendingOnEndAction = null;
  751.         }
  752.         animator.addUpdateListener(mAnimatorEventListener);
  753.         animator.addListener(mAnimatorEventListener);
  754.         if (mStartDelaySet) {
  755.             animator.setStartDelay(mStartDelay);
  756.         }
  757.         if (mDurationSet) {
  758.             animator.setDuration(mDuration);
  759.         }
  760.         if (mInterpolatorSet) {
  761.             animator.setInterpolator(mInterpolator);
  762.         }
  763.         animator.start();
  764.     }
  765.  
  766.     /**
  767.      * Utility function, called by the various x(), y(), etc. methods. This stores the
  768.      * constant name for the property along with the from/delta values that will be used to
  769.      * calculate and set the property during the animation. This structure is added to the
  770.      * pending animations, awaiting the eventual start() of the underlying animator. A
  771.      * Runnable is posted to start the animation, and any pending such Runnable is canceled
  772.      * (which enables us to end up starting just one animator for all of the properties
  773.      * specified at one time).
  774.      *
  775.      * @param constantName The specifier for the property being animated
  776.      * @param toValue The value to which the property will animate
  777.      */
  778.     private void animateProperty(int constantName, float toValue) {
  779.         float fromValue = getValue(constantName);
  780.         float deltaValue = toValue - fromValue;
  781.         animatePropertyBy(constantName, fromValue, deltaValue);
  782.     }
  783.  
  784.     /**
  785.      * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
  786.      * just like animateProperty(), except the value is an offset from the property's
  787.      * current value, instead of an absolute "to" value.
  788.      *
  789.      * @param constantName The specifier for the property being animated
  790.      * @param byValue The amount by which the property will change
  791.      */
  792.     private void animatePropertyBy(int constantName, float byValue) {
  793.         float fromValue = getValue(constantName);
  794.         animatePropertyBy(constantName, fromValue, byValue);
  795.     }
  796.  
  797.     /**
  798.      * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
  799.      * details of adding a pending animation and posting the request to start the animation.
  800.      *
  801.      * @param constantName The specifier for the property being animated
  802.      * @param startValue The starting value of the property
  803.      * @param byValue The amount by which the property will change
  804.      */
  805.     private void animatePropertyBy(int constantName, float startValue, float byValue) {
  806.         // First, cancel any existing animations on this property
  807.         if (mAnimatorMap.size() > 0) {
  808.             Animator animatorToCancel = null;
  809.             Set<Animator> animatorSet = mAnimatorMap.keySet();
  810.             for (Animator runningAnim : animatorSet) {
  811.                 PropertyBundle bundle = mAnimatorMap.get(runningAnim);
  812.                 if (bundle.cancel(constantName)) {
  813.                     // property was canceled - cancel the animation if it's now empty
  814.                     // Note that it's safe to break out here because every new animation
  815.                     // on a property will cancel a previous animation on that property, so
  816.                     // there can only ever be one such animation running.
  817.                     if (bundle.mPropertyMask == NONE) {
  818.                         // the animation is no longer changing anything - cancel it
  819.                         animatorToCancel = runningAnim;
  820.                         break;
  821.                     }
  822.                 }
  823.             }
  824.             if (animatorToCancel != null) {
  825.                 animatorToCancel.cancel();
  826.             }
  827.         }
  828.  
  829.         NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
  830.         mPendingAnimations.add(nameValuePair);
  831.         mView.removeCallbacks(mAnimationStarter);
  832.         mView.post(mAnimationStarter);
  833.     }
  834.  
  835.     /**
  836.      * This method handles setting the property values directly in the View object's fields.
  837.      * propertyConstant tells it which property should be set, value is the value to set
  838.      * the property to.
  839.      *
  840.      * @param propertyConstant The property to be set
  841.      * @param value The value to set the property to
  842.      */
  843.     private void setValue(int propertyConstant, float value) {
  844.         final View.TransformationInfo info = mView.mTransformationInfo;
  845.         final DisplayList displayList = mView.mDisplayList;
  846.         switch (propertyConstant) {
  847.             case TRANSLATION_X:
  848.                 info.mTranslationX = value;
  849.                 if (displayList != null) displayList.setTranslationX(value);
  850.                 break;
  851.             case TRANSLATION_Y:
  852.                 info.mTranslationY = value;
  853.                 if (displayList != null) displayList.setTranslationY(value);
  854.                 break;
  855.             case ROTATION:
  856.                 info.mRotation = value;
  857.                 if (displayList != null) displayList.setRotation(value);
  858.                 break;
  859.             case ROTATION_X:
  860.                 info.mRotationX = value;
  861.                 if (displayList != null) displayList.setRotationX(value);
  862.                 break;
  863.             case ROTATION_Y:
  864.                 info.mRotationY = value;
  865.                 if (displayList != null) displayList.setRotationY(value);
  866.                 break;
  867.             case SCALE_X:
  868.                 info.mScaleX = value;
  869.                 if (displayList != null) displayList.setScaleX(value);
  870.                 break;
  871.             case SCALE_Y:
  872.                 info.mScaleY = value;
  873.                 if (displayList != null) displayList.setScaleY(value);
  874.                 break;
  875.             case X:
  876.                 info.mTranslationX = value - mView.mLeft;
  877.                 if (displayList != null) displayList.setTranslationX(value - mView.mLeft);
  878.                 break;
  879.             case Y:
  880.                 info.mTranslationY = value - mView.mTop;
  881.                 if (displayList != null) displayList.setTranslationY(value - mView.mTop);
  882.                 break;
  883.             case ALPHA:
  884.                 info.mAlpha = value;
  885.                 if (displayList != null) displayList.setAlpha(value);
  886.                 break;
  887.         }
  888.     }
  889.  
  890.     /**
  891.      * This method gets the value of the named property from the View object.
  892.      *
  893.      * @param propertyConstant The property whose value should be returned
  894.      * @return float The value of the named property
  895.      */
  896.     private float getValue(int propertyConstant) {
  897.         final View.TransformationInfo info = mView.mTransformationInfo;
  898.         switch (propertyConstant) {
  899.             case TRANSLATION_X:
  900.                 return info.mTranslationX;
  901.             case TRANSLATION_Y:
  902.                 return info.mTranslationY;
  903.             case ROTATION:
  904.                 return info.mRotation;
  905.             case ROTATION_X:
  906.                 return info.mRotationX;
  907.             case ROTATION_Y:
  908.                 return info.mRotationY;
  909.             case SCALE_X:
  910.                 return info.mScaleX;
  911.             case SCALE_Y:
  912.                 return info.mScaleY;
  913.             case X:
  914.                 return mView.mLeft + info.mTranslationX;
  915.             case Y:
  916.                 return mView.mTop + info.mTranslationY;
  917.             case ALPHA:
  918.                 return info.mAlpha;
  919.         }
  920.         return 0;
  921.     }
  922.  
  923.     /**
  924.      * Utility class that handles the various Animator events. The only ones we care
  925.      * about are the end event (which we use to clean up the animator map when an animator
  926.      * finishes) and the update event (which we use to calculate the current value of each
  927.      * property and then set it on the view object).
  928.      */
  929.     private class AnimatorEventListener
  930.             implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
  931.         @Override
  932.         public void onAnimationStart(Animator animation) {
  933.             if (mAnimatorSetupMap != null) {
  934.                 Runnable r = mAnimatorSetupMap.get(animation);
  935.                 if (r != null) {
  936.                     r.run();
  937.                 }
  938.                 mAnimatorSetupMap.remove(animation);
  939.             }
  940.             if (mAnimatorOnStartMap != null) {
  941.                 Runnable r = mAnimatorOnStartMap.get(animation);
  942.                 if (r != null) {
  943.                     r.run();
  944.                 }
  945.                 mAnimatorOnStartMap.remove(animation);
  946.             }
  947.             if (mListener != null) {
  948.                 mListener.onAnimationStart(animation);
  949.             }
  950.         }
  951.  
  952.         @Override
  953.         public void onAnimationCancel(Animator animation) {
  954.             if (mListener != null) {
  955.                 mListener.onAnimationCancel(animation);
  956.             }
  957.             if (mAnimatorOnEndMap != null) {
  958.                 mAnimatorOnEndMap.remove(animation);
  959.             }
  960.         }
  961.  
  962.         @Override
  963.         public void onAnimationRepeat(Animator animation) {
  964.             if (mListener != null) {
  965.                 mListener.onAnimationRepeat(animation);
  966.             }
  967.         }
  968.  
  969.         @Override
  970.         public void onAnimationEnd(Animator animation) {
  971.             mView.setHasTransientState(false);
  972.             if (mListener != null) {
  973.                 mListener.onAnimationEnd(animation);
  974.             }
  975.             if (mAnimatorOnEndMap != null) {
  976.                 Runnable r = mAnimatorOnEndMap.get(animation);
  977.                 if (r != null) {
  978.                     r.run();
  979.                 }
  980.                 mAnimatorOnEndMap.remove(animation);
  981.             }
  982.             if (mAnimatorCleanupMap != null) {
  983.                 Runnable r = mAnimatorCleanupMap.get(animation);
  984.                 if (r != null) {
  985.                     r.run();
  986.                 }
  987.                 mAnimatorCleanupMap.remove(animation);
  988.             }
  989.             mAnimatorMap.remove(animation);
  990.         }
  991.  
  992.         /**
  993.          * Calculate the current value for each property and set it on the view. Invalidate
  994.          * the view object appropriately, depending on which properties are being animated.
  995.          *
  996.          * @param animation The animator associated with the properties that need to be
  997.          * set. This animator holds the animation fraction which we will use to calculate
  998.          * the current value of each property.
  999.          */
  1000.         @Override
  1001.         public void onAnimationUpdate(ValueAnimator animation) {
  1002.             PropertyBundle propertyBundle = mAnimatorMap.get(animation);
  1003.             if (propertyBundle == null) {
  1004.                 // Shouldn't happen, but just to play it safe
  1005.                 return;
  1006.             }
  1007.             boolean useDisplayListProperties = mView.mDisplayList != null;
  1008.  
  1009.             // alpha requires slightly different treatment than the other (transform) properties.
  1010.             // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
  1011.             // logic is dependent on how the view handles an internal call to onSetAlpha().
  1012.             // We track what kinds of properties are set, and how alpha is handled when it is
  1013.             // set, and perform the invalidation steps appropriately.
  1014.             boolean alphaHandled = false;
  1015.             if (!useDisplayListProperties) {
  1016.                 mView.invalidateParentCaches();
  1017.             }
  1018.             float fraction = animation.getAnimatedFraction();
  1019.             int propertyMask = propertyBundle.mPropertyMask;
  1020.             if ((propertyMask & TRANSFORM_MASK) != 0) {
  1021.                 mView.invalidateViewProperty(false, false);
  1022.             }
  1023.             ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
  1024.             if (valueList != null) {
  1025.                 int count = valueList.size();
  1026.                 for (int i = 0; i < count; ++i) {
  1027.                     NameValuesHolder values = valueList.get(i);
  1028.                     float value = values.mFromValue + fraction * values.mDeltaValue;
  1029.                     if (values.mNameConstant == ALPHA) {
  1030.                         alphaHandled = mView.setAlphaNoInvalidation(value);
  1031.                     } else {
  1032.                         setValue(values.mNameConstant, value);
  1033.                     }
  1034.                 }
  1035.             }
  1036.             if ((propertyMask & TRANSFORM_MASK) != 0) {
  1037.                 mView.mTransformationInfo.mMatrixDirty = true;
  1038.                 if (!useDisplayListProperties) {
  1039.                     mView.mPrivateFlags |= View.DRAWN; // force another invalidation
  1040.                 }
  1041.             }
  1042.             // invalidate(false) in all cases except if alphaHandled gets set to true
  1043.             // via the call to setAlphaNoInvalidation(), above
  1044.             if (alphaHandled) {
  1045.                 mView.invalidate(true);
  1046.             } else {
  1047.                 mView.invalidateViewProperty(false, false);
  1048.             }
  1049.         }
  1050.     }
  1051. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement