summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml332
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java16
-rw-r--r--core/java/android/view/View.java60
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java745
4 files changed, 1141 insertions, 12 deletions
diff --git a/api/current.xml b/api/current.xml
index 5ceca12..1089604 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -21153,6 +21153,17 @@
<parameter name="listener" type="android.animation.ValueAnimator.AnimatorUpdateListener">
</parameter>
</method>
+<method name="getAnimatedFraction"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getAnimatedValue"
return="java.lang.Object"
abstract="false"
@@ -220391,6 +220402,17 @@
<parameter name="views" type="java.util.ArrayList&lt;android.view.View&gt;">
</parameter>
</method>
+<method name="animate"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="awakenScrollBars"
return="boolean"
abstract="false"
@@ -228642,6 +228664,314 @@
</parameter>
</method>
</interface>
+<class name="ViewPropertyAnimator"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="alpha"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="alphaBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotation"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationX"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationXBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationY"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationYBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleX"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleXBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleY"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleYBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="setDuration"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="setInterpolator"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="interpolator" type="android.animation.TimeInterpolator">
+</parameter>
+</method>
+<method name="setListener"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.animation.Animator.AnimatorListener">
+</parameter>
+</method>
+<method name="translationX"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="translationXBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="translationY"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="translationYBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="x"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="xBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="y"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="yBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+</class>
<class name="ViewStub"
extends="android.view.View"
abstract="false"
@@ -266083,7 +266413,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index b963117..f562851 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -160,6 +160,11 @@ public class ValueAnimator extends Animator {
private int mCurrentIteration = 0;
/**
+ * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
+ */
+ private float mCurrentFraction = 0f;
+
+ /**
* Tracks whether a startDelay'd animation has begun playing through the startDelay.
*/
private boolean mStartedDelay = false;
@@ -1111,6 +1116,16 @@ public class ValueAnimator extends Animator {
}
/**
+ * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
+ * the most recent frame update on the animation.
+ *
+ * @return Elapsed/interpolated fraction of the animation.
+ */
+ public float getAnimatedFraction() {
+ return mCurrentFraction;
+ }
+
+ /**
* This method is called with the elapsed fraction of the animation during every
* animation frame. This function turns the elapsed fraction into an interpolated fraction
* and then into an animated value (from the evaluator. The function is called mostly during
@@ -1124,6 +1139,7 @@ public class ValueAnimator extends Animator {
*/
void animateValue(float fraction) {
fraction = mInterpolator.getInterpolation(fraction);
+ mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].calculateValue(fraction);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e18c5e0..65d93a6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1866,7 +1866,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* transform matrix, based on whether the rotation or scaleX/Y properties
* have changed since the matrix was last calculated.
*/
- private boolean mMatrixDirty = false;
+ boolean mMatrixDirty = false;
/**
* An internal variable that tracks whether we need to recalculate the
@@ -1914,66 +1914,66 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* The degrees rotation around the vertical axis through the pivot point.
*/
@ViewDebug.ExportedProperty
- private float mRotationY = 0f;
+ float mRotationY = 0f;
/**
* The degrees rotation around the horizontal axis through the pivot point.
*/
@ViewDebug.ExportedProperty
- private float mRotationX = 0f;
+ float mRotationX = 0f;
/**
* The degrees rotation around the pivot point.
*/
@ViewDebug.ExportedProperty
- private float mRotation = 0f;
+ float mRotation = 0f;
/**
* The amount of translation of the object away from its left property (post-layout).
*/
@ViewDebug.ExportedProperty
- private float mTranslationX = 0f;
+ float mTranslationX = 0f;
/**
* The amount of translation of the object away from its top property (post-layout).
*/
@ViewDebug.ExportedProperty
- private float mTranslationY = 0f;
+ float mTranslationY = 0f;
/**
* The amount of scale in the x direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mScaleX = 1f;
+ float mScaleX = 1f;
/**
* The amount of scale in the y direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mScaleY = 1f;
+ float mScaleY = 1f;
/**
* The amount of scale in the x direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mPivotX = 0f;
+ float mPivotX = 0f;
/**
* The amount of scale in the y direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mPivotY = 0f;
+ float mPivotY = 0f;
/**
* The opacity of the View. This is a value from 0 to 1, where 0 means
* completely transparent and 1 means completely opaque.
*/
@ViewDebug.ExportedProperty
- private float mAlpha = 1f;
+ float mAlpha = 1f;
/**
* The distance in pixels from the left edge of this view's parent
@@ -2237,6 +2237,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
private int mTouchSlop;
/**
+ * Object that handles automatic animation of view properties.
+ */
+ private ViewPropertyAnimator mAnimator = null;
+
+ /**
* Cache drag/drop state
*
*/
@@ -6157,6 +6162,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * Faster version of setAlpha() which performs the same steps except there are
+ * no calls to invalidate(). The caller of this function should perform proper invalidation
+ * on the parent and this object. The return value indicates whether the subclass handles
+ * alpha (the return value for onSetAlpha()).
+ *
+ * @param alpha The new value for the alpha property
+ * @return true if the View subclass handles alpha (the return value for onSetAlpha())
+ */
+ boolean setAlphaNoInvalidation(float alpha) {
+ mAlpha = alpha;
+ boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255));
+ if (subclassHandlesAlpha) {
+ mPrivateFlags |= ALPHA_SET;
+ } else {
+ mPrivateFlags &= ~ALPHA_SET;
+ }
+ return subclassHandlesAlpha;
+ }
+
+ /**
* Top position of this view relative to its parent.
*
* @return The top of this view, in pixels.
@@ -11785,6 +11810,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * This method returns a ViewPropertyAnimator object, which can be used to animate
+ * specific properties on this View.
+ *
+ * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
+ */
+ public ViewPropertyAnimator animate() {
+ if (mAnimator == null) {
+ mAnimator = new ViewPropertyAnimator(this);
+ }
+ return mAnimator;
+ }
+
+ /**
* Interface definition for a callback to be invoked when a key event is
* dispatched to this view. The callback will be invoked before the key
* event is given to the view.
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
new file mode 100644
index 0000000..cc00f94
--- /dev/null
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.animation.TimeInterpolator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+/**
+ * This class enables automatic and optimized animation of select properties on View objects.
+ * If only one or two properties on a View object are being animated, then using an
+ * {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
+ * are well equipped to do the right thing to set the property and invalidate the view
+ * appropriately. But if several properties are animated simultaneously, or if you just want a
+ * more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
+ * more well-suited to the task.
+ *
+ * <p>This class could provide better performance for several simultaneous animations, because
+ * it will optimize invalidatesionto take place only once for several properties instead of each
+ * aniamted property independently causing its own invalidation. Also, the syntax of using this
+ * class could be easier to use because the caller need only tell the View object which
+ * property to animate, and the value to animate either to or by, and this calss handles the
+ * details of configuring the underlying Animator class and starting it.</p>
+ *
+ * <p>This class is not constructed by the caller, but rather by the View whose properties
+ * it will animate. Calls to {@link android.view.View#animate()} will return a reference
+ * to the appropriate ViewPropertyAnimator object for that View.</p>
+ *
+ */
+public class ViewPropertyAnimator {
+
+ /**
+ * The View whose properties are being animated by this class. This is set at
+ * construction time.
+ */
+ private View mView;
+
+ /**
+ * The duration of the underlying Animator object. By default, we don't set the duration
+ * on the Animator and just use its default duration. If the duration is ever set on this
+ * Animator, then we use the duration that it was set to.
+ */
+ private long mDuration;
+
+ /**
+ * A flag indicating whether the duration has been set on this object. If not, we don't set
+ * the duration on the underlying Animator, but instead just use its default duration.
+ */
+ private boolean mDurationSet = false;
+
+ /**
+ * The interpolator of the underlying Animator object. By default, we don't set the interpolator
+ * on the Animator and just use its default interpolator. If the interpolator is ever set on
+ * this Animator, then we use the interpolator that it was set to.
+ */
+ private TimeInterpolator mInterpolator;
+
+ /**
+ * A flag indicating whether the interpolator has been set on this object. If not, we don't set
+ * the interpolator on the underlying Animator, but instead just use its default interpolator.
+ */
+ private boolean mInterpolatorSet = false;
+
+ /**
+ * Listener for the lifecycle events of the underlying
+ */
+ private Animator.AnimatorListener mListener = null;
+
+ /**
+ * This listener is the mechanism by which the underlying Animator causes changes to the
+ * properties currently being animated, as well as the cleanup after an animation is
+ * complete.
+ */
+ private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
+
+ /**
+ * This list holds the properties that have been asked to animate. We allow the caller to
+ * request several animations prior to actually starting the underlying animator. This
+ * enables us to run one single animator to handle several properties in parallel. Each
+ * property is tossed onto the pending list until the animation actually starts (which is
+ * done by posting it onto mView), at which time the pending list is cleared and the properties
+ * on that list are added to the list of properties associated with that animator.
+ */
+ ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
+
+ /**
+ * Constants used to associate a property being requested and the mechanism used to set
+ * the property (this calss calls directly into View to set the properties in question).
+ */
+ private static final int NONE = 0x0000;
+ private static final int TRANSLATION_X = 0x0001;
+ private static final int TRANSLATION_Y = 0x0002;
+ private static final int SCALE_X = 0x0004;
+ private static final int SCALE_Y = 0x0008;
+ private static final int ROTATION = 0x0010;
+ private static final int ROTATION_X = 0x0020;
+ private static final int ROTATION_Y = 0x0040;
+ private static final int X = 0x0080;
+ private static final int Y = 0x0100;
+ private static final int ALPHA = 0x0200;
+
+ private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
+ ROTATION | ROTATION_X | ROTATION_Y | X | Y;
+
+ /**
+ * The mechanism by which the user can request several properties that are then animated
+ * together works by posting this Runnable to start the underlying Animator. Every time
+ * a property animation is requested, we cancel any previous postings of the Runnable
+ * and re-post it. This means that we will only ever run the Runnable (and thus start the
+ * underlying animator) after the caller is done setting the properties that should be
+ * animated together.
+ */
+ private Runnable mAnimationStarter = new Runnable() {
+ @Override
+ public void run() {
+ startAnimation();
+ }
+ };
+
+ /**
+ * This class holds information about the overall animation being run on the set of
+ * properties. The mask describes which properties are being animated and the
+ * values holder is the list of all property/value objects.
+ */
+ private static class PropertyBundle {
+ int mPropertyMask;
+ ArrayList<NameValuesHolder> mNameValuesHolder;
+ PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
+ mPropertyMask = propertyMask;
+ mNameValuesHolder = nameValuesHolder;
+ }
+ }
+
+ /**
+ * This list tracks the list of properties being animated by any particular animator.
+ * In most situations, there would only ever be one animator running at a time. But it is
+ * possible to request some properties to animate together, then while those properties
+ * are animating, to request some other properties to animate together. The way that
+ * works is by having this map associate the group of properties being animated with the
+ * animator handling the animation. On every update event for an Animator, we ask the
+ * map for the associated properties and set them accordingly.
+ */
+ private HashMap<Animator, PropertyBundle> mAnimatorMap =
+ new HashMap<Animator, PropertyBundle>();
+
+ /**
+ * This is the information we need to set each property during the animation.
+ * mNameConstant is used to set the appropriate field in View, and the from/delta
+ * values are used to calculate the animated value for a given animation fraction
+ * during the animation.
+ */
+ private static class NameValuesHolder {
+ int mNameConstant;
+ float mFromValue;
+ float mDeltaValue;
+ NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
+ mNameConstant = nameConstant;
+ mFromValue = fromValue;
+ mDeltaValue = deltaValue;
+ }
+ }
+
+ /**
+ * Constructor, called by View. This is private by design, as the user should only
+ * get a ViewPropertyAnimator by calling View.animate().
+ *
+ * @param view The View associated with this ViewPropertyAnimator
+ */
+ ViewPropertyAnimator(View view) {
+ mView = view;
+ }
+
+ /**
+ * Sets the duration for the underlying animator that animates the requested properties.
+ * By default, the animator uses the default value for ValueAnimator. Calling this method
+ * will cause the declared value to be used instead.
+ * @param duration The length of ensuing property animations, in milliseconds. The value
+ * cannot be negative.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setDuration(long duration) {
+ if (duration < 0) {
+ throw new IllegalArgumentException("Animators cannot have negative duration: " +
+ duration);
+ }
+ mDurationSet = true;
+ mDuration = duration;
+ return this;
+ }
+
+ /**
+ * Sets the interpolator for the underlying animator that animates the requested properties.
+ * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
+ * will cause the declared object to be used instead.
+ *
+ * @param interpolator The TimeInterpolator to be used for ensuing property animations.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
+ mInterpolatorSet = true;
+ mInterpolator = interpolator;
+ return this;
+ }
+
+ /**
+ * Sets a listener for events in the underlying Animators that run the property
+ * animations.
+ *
+ * @param listener The listener to be called with AnimatorListener events.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
+ mListener = listener;
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>x</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator x(float value) {
+ animateProperty(X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>x</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator xBy(float value) {
+ animatePropertyBy(X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>y</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator y(float value) {
+ animateProperty(Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>y</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator yBy(float value) {
+ animatePropertyBy(Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotation</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setRotation(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotation(float value) {
+ animateProperty(ROTATION, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotation</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setRotation(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationBy(float value) {
+ animatePropertyBy(ROTATION, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationX</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setRotationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationX(float value) {
+ animateProperty(ROTATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationX</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setRotationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationXBy(float value) {
+ animatePropertyBy(ROTATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationY</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setRotationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationY(float value) {
+ animateProperty(ROTATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationY</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setRotationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationYBy(float value) {
+ animatePropertyBy(ROTATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationX</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setTranslationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationX(float value) {
+ animateProperty(TRANSLATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationX</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setTranslationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationXBy(float value) {
+ animatePropertyBy(TRANSLATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationY</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setTranslationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationY(float value) {
+ animateProperty(TRANSLATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationY</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setTranslationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationYBy(float value) {
+ animatePropertyBy(TRANSLATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleX</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setScaleX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleX(float value) {
+ animateProperty(SCALE_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleX</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setScaleX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleXBy(float value) {
+ animatePropertyBy(SCALE_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleY</code> property to be animated to the
+ * specifed value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setScaleY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleY(float value) {
+ animateProperty(SCALE_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleY</code> property to be animated by the
+ * specifed value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setScaleY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleYBy(float value) {
+ animatePropertyBy(SCALE_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>alpha</code> property to be animated to the
+ * specified value.
+ *
+ * @param value The value to be animated to.
+ * @see View#setAlpha(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator alpha(float value) {
+ animateProperty(ALPHA, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>alpha</code> property to be animated by the
+ * specified value.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setAlpha(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator alphaBy(float value) {
+ animatePropertyBy(ALPHA, value);
+ return this;
+ }
+
+ /**
+ * Starts the underlying Animator for a set of properties. We use a single animator that
+ * simply runs from 0 to 1, and then use that fractional value to set each property
+ * value accordingly.
+ */
+ private void startAnimation() {
+ ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
+ ArrayList<NameValuesHolder> nameValueList =
+ (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
+ mPendingAnimations.clear();
+ int propertyMask = 0;
+ int propertyCount = nameValueList.size();
+ for (int i = 0; i < propertyCount; ++i) {
+ NameValuesHolder nameValuesHolder = nameValueList.get(i);
+ propertyMask |= nameValuesHolder.mNameConstant;
+ }
+ // First, cancel any running animation on the same property set
+ if (mAnimatorMap.size() > 0) {
+ Animator animatorToCancel = null;
+ Set<Animator> animatorSet = mAnimatorMap.keySet();
+ for (Animator runningAnim : animatorSet) {
+ PropertyBundle bundle = mAnimatorMap.get(runningAnim);
+ if (bundle.mPropertyMask == propertyMask) {
+ // There can be only one such duplicate, because that animation would
+ // have caused previous ones to cancel prior to starting. So break when we
+ // find one.
+ animatorToCancel = runningAnim;
+ break;
+ }
+ }
+ if (animatorToCancel != null) {
+ animatorToCancel.cancel();
+ }
+ }
+ mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
+ animator.addUpdateListener(mAnimatorEventListener);
+ animator.addListener(mAnimatorEventListener);
+ if (mDurationSet) {
+ animator.setDuration(mDuration);
+ }
+ if (mInterpolatorSet) {
+ animator.setInterpolator(mInterpolator);
+ }
+ animator.start();
+ }
+
+ /**
+ * Utility function, called by the various x(), y(), etc. methods. This stores the
+ * constnat name for the property along with the from/delta values that will be used to
+ * calculate and set the property during the animation. This structure is added to the
+ * pending animations, awaiting the eventual start() of the underlying animator. A
+ * Runnable is posted to start the animation, and any pending such Runnable is canceled
+ * (which enables us to end up starting just one animator for all of the properties
+ * specified at one time).
+ *
+ * @param constantName The specifier for the property being animated
+ * @param toValue The value to which the property will animate
+ */
+ private void animateProperty(int constantName, float toValue) {
+ float fromValue = getValue(constantName);
+ float deltaValue = toValue - fromValue;
+ animatePropertyBy(constantName, fromValue, deltaValue);
+ }
+
+ /**
+ * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
+ * just like animateProperty(), except the value is an offset from the property's
+ * current value, instead of an absolute "to" value.
+ *
+ * @param constantName The specifier for the property being animated
+ * @param byValue The amount by which the property will change
+ */
+ private void animatePropertyBy(int constantName, float byValue) {
+ float fromValue = getValue(constantName);
+ animatePropertyBy(constantName, fromValue, byValue);
+ }
+
+ /**
+ * Utility function, called by animatePropert() and animatePropertyBy(), which handles the
+ * details of adding a pending animation and posting the request to start the animation.
+ *
+ * @param constantName The specifier for the property being animated
+ * @param fromValue The starting value of the property
+ * @param byValue The amount by which the property will change
+ */
+ private void animatePropertyBy(int constantName, float fromValue, float byValue) {
+ float startValue = getValue(constantName);
+ NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
+ mPendingAnimations.add(nameValuePair);
+ mView.getHandler().removeCallbacks(mAnimationStarter);
+ mView.post(mAnimationStarter);
+ }
+
+ /**
+ * This method handles setting the property values directly in the View object's fields.
+ * propertyConstant tells it which property should be set, value is the value to set
+ * the property to.
+ *
+ * @param propertyConstant The property to be set
+ * @param value The value to set the property to
+ */
+ private void setValue(int propertyConstant, float value) {
+ switch (propertyConstant) {
+ case TRANSLATION_X:
+ mView.mTranslationX = value;
+ break;
+ case TRANSLATION_Y:
+ mView.mTranslationY = value;
+ break;
+ case ROTATION:
+ mView.mRotation = value;
+ break;
+ case ROTATION_X:
+ mView.mRotationX = value;
+ break;
+ case ROTATION_Y:
+ mView.mRotationY = value;
+ break;
+ case SCALE_X:
+ mView.mScaleX = value;
+ break;
+ case SCALE_Y:
+ mView.mScaleY = value;
+ break;
+ case X:
+ mView.mTranslationX = value - mView.mLeft;
+ break;
+ case Y:
+ mView.mTranslationY = value - mView.mTop;
+ break;
+ case ALPHA:
+ mView.mAlpha = value;
+ break;
+ }
+ }
+
+ /**
+ * This method gets the value of the named property from the View object.
+ *
+ * @param propertyConstant The property whose value should be returned
+ * @return float The value of the named property
+ */
+ private float getValue(int propertyConstant) {
+ switch (propertyConstant) {
+ case TRANSLATION_X:
+ return mView.mTranslationX;
+ case TRANSLATION_Y:
+ return mView.mTranslationY;
+ case ROTATION:
+ return mView.mRotation;
+ case ROTATION_X:
+ return mView.mRotationX;
+ case ROTATION_Y:
+ return mView.mRotationY;
+ case SCALE_X:
+ return mView.mScaleX;
+ case SCALE_Y:
+ return mView.mScaleY;
+ case X:
+ return mView.mLeft + mView.mTranslationX;
+ case Y:
+ return mView.mTop + mView.mTranslationY;
+ case ALPHA:
+ return mView.mAlpha;
+ }
+ return 0;
+ }
+
+ /**
+ * Utility class that handles the various Animator events. The only ones we care
+ * about are the end event (which we use to clean up the animator map when an animator
+ * finishes) and the update event (which we use to calculate the current value of each
+ * property and then set it on the view object).
+ */
+ private class AnimatorEventListener
+ implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationStart(animation);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationCancel(animation);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationRepeat(animation);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationEnd(animation);
+ }
+ mAnimatorMap.remove(animation);
+ }
+
+ /**
+ * Calculate the current value for each property and set it on the view. Invalidate
+ * the view object appropriately, depending on which properties are being animated.
+ *
+ * @param animation The animator associated with the properties that need to be
+ * set. This animator holds the animation fraction which we will use to calculate
+ * the current value of each property.
+ */
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ // alpha requires slightly different treatment than the other (transform) properties.
+ // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
+ // logic is dependent on how the view handles an internal call to onSetAlpha().
+ // We track what kinds of properties are set, and how alpha is handled when it is
+ // set, and perform the invalidation steps appropriately.
+ boolean alphaHandled = false;
+ mView.invalidateParentCaches();
+ float fraction = animation.getAnimatedFraction();
+ PropertyBundle propertyBundle = mAnimatorMap.get(animation);
+ int propertyMask = propertyBundle.mPropertyMask;
+ if ((propertyMask & TRANSFORM_MASK) != 0) {
+ mView.invalidate(false);
+ }
+ ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
+ if (valueList != null) {
+ int count = valueList.size();
+ for (int i = 0; i < count; ++i) {
+ NameValuesHolder values = valueList.get(i);
+ float value = values.mFromValue + fraction * values.mDeltaValue;
+ if (values.mNameConstant == ALPHA) {
+ alphaHandled = mView.setAlphaNoInvalidation(value);
+ } else {
+ setValue(values.mNameConstant, value);
+ }
+ }
+ }
+ if ((propertyMask & TRANSFORM_MASK) != 0) {
+ mView.mMatrixDirty = true;
+ mView.mPrivateFlags |= View.DRAWN; // force another invalidation
+ }
+ // invalidate(false) in all cases except if alphaHandled gets set to true
+ // via the call to setAlphaNoInvalidation(), above
+ mView.invalidate(alphaHandled);
+ }
+ }
+}