Add keyframes to animation framework.
Change-Id: I5c8c8037aeeedae1ce7a18200986caf57264772f
This commit is contained in:
@@ -189,6 +189,11 @@ public class Animator extends Animatable {
|
||||
*/
|
||||
private Object mAnimatedValue = null;
|
||||
|
||||
/**
|
||||
* The set of keyframes (time/value pairs) that define this animation.
|
||||
*/
|
||||
private KeyframeSet mKeyframeSet = null;
|
||||
|
||||
/**
|
||||
* The type of the values, as determined by the valueFrom/valueTo properties.
|
||||
*/
|
||||
@@ -221,6 +226,20 @@ public class Animator extends Animatable {
|
||||
this.mValueType = valueType;
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor takes a set of {@link Keyframe} objects that define the values
|
||||
* for the animation, along with the times at which those values will hold true during
|
||||
* the animation.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
* @param keyframes The set of keyframes that define the time/value pairs for the animation.
|
||||
*/
|
||||
public Animator(long duration, Keyframe...keyframes) {
|
||||
mDuration = duration;
|
||||
mKeyframeSet = new KeyframeSet(keyframes);
|
||||
mValueType = keyframes[0].getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called immediately before processing the first animation
|
||||
* frame of an animation. If there is a nonzero <code>startDelay</code>, the
|
||||
@@ -420,6 +439,15 @@ public class Animator extends Animatable {
|
||||
return sFrameDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of keyframes that define this animation.
|
||||
*
|
||||
* @return KeyframeSet The set of keyframes for this animation.
|
||||
*/
|
||||
KeyframeSet getKeyframes() {
|
||||
return mKeyframeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value that this animation will start from.
|
||||
*
|
||||
@@ -751,7 +779,11 @@ public class Animator extends Animatable {
|
||||
*/
|
||||
void animateValue(float fraction) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
mAnimatedValue = mEvaluator.evaluate(fraction, mValueFrom, mValueTo);
|
||||
if (mKeyframeSet != null) {
|
||||
mAnimatedValue = mKeyframeSet.getValue(fraction, mEvaluator);
|
||||
} else {
|
||||
mAnimatedValue = mEvaluator.evaluate(fraction, mValueFrom, mValueTo);
|
||||
}
|
||||
if (mUpdateListeners != null) {
|
||||
int numListeners = mUpdateListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
|
||||
185
core/java/android/animation/Keyframe.java
Normal file
185
core/java/android/animation/Keyframe.java
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This class represents timea time/value pair for an animation. The Keyframe class is used
|
||||
* by {@link Animator} to define the values that the animation target will have over the course
|
||||
* of the animation. As the time proceeds from one keyframe to the other, the value of the
|
||||
* target object will animate between the value at the previous keyframe and the value at the
|
||||
* next keyframe. Each keyframe also holds an option {@link android.view.animation.Interpolator}
|
||||
* object, which defines the time interpolation over the intervalue preceding the keyframe.
|
||||
*/
|
||||
public class Keyframe {
|
||||
/**
|
||||
* The time at which mValue will hold true.
|
||||
*/
|
||||
private float mFraction;
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
private Object mValue;
|
||||
|
||||
/**
|
||||
* The type of the value in this Keyframe. This type is determined at construction time,
|
||||
* based on the type of the <code>value</code> object passed into the constructor.
|
||||
*/
|
||||
private Class mValueType;
|
||||
|
||||
/**
|
||||
* The optional time interpolator for the interval preceding this keyframe. A null interpolator
|
||||
* (the default) results in linear interpolation over the interval.
|
||||
*/
|
||||
private Interpolator mInterpolator = null;
|
||||
|
||||
/**
|
||||
* Private constructor, called from the public constructors with the additional
|
||||
* <code>valueType</code> parameter.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
* @param valueType The type of the <code>value</code> object. This is used by the
|
||||
* {@link #getValue()} functionm, which is queried by {@link Animator} to determine
|
||||
* the type of {@link TypeEvaluator} to use to interpolate between values.
|
||||
*/
|
||||
private Keyframe(float fraction, Object value, Class valueType) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = valueType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public Keyframe(float fraction, Object value) {
|
||||
this(fraction, value, Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and integer value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public Keyframe(float fraction, int value) {
|
||||
this(fraction, value, int.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and float value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public Keyframe(float fraction, float value) {
|
||||
this(fraction, value, float.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and double value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public Keyframe(float fraction, double value) {
|
||||
this(fraction, value, double.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for this Keyframe.
|
||||
*
|
||||
* @return The value for this Keyframe.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @return The time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public float getFraction() {
|
||||
return mFraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public Interpolator getInterpolator() {
|
||||
return mInterpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public void setInterpolator(Interpolator interpolator) {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of keyframe. This information is used by Animator to determine the type of
|
||||
* {@linke TypeEvaluator} to use when calculating values between keyframes. The type is based
|
||||
* on the type of Keyframe created. For example, {@link IntKeyframe} returns a value of
|
||||
* <code>int.class</code>. This superclass returns a value of <code>Object.class</code>.
|
||||
*
|
||||
* @return The type of the value stored in the Keyframe.
|
||||
*/
|
||||
public Class getType() {
|
||||
return mValueType;
|
||||
}
|
||||
}
|
||||
99
core/java/android/animation/KeyframeSet.java
Normal file
99
core/java/android/animation/KeyframeSet.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This class holds a collection of Keyframe objects and is called by Animator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*/
|
||||
class KeyframeSet {
|
||||
|
||||
private int mNumKeyframes;
|
||||
|
||||
private ArrayList<Keyframe> mKeyframes;
|
||||
|
||||
public KeyframeSet(Keyframe... keyframes) {
|
||||
mKeyframes = new ArrayList<Keyframe>();
|
||||
for (Keyframe keyframe : keyframes) {
|
||||
mKeyframes.add(keyframe);
|
||||
}
|
||||
mNumKeyframes = mKeyframes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animated value, given the elapsed fraction of the animation (interpolated by the
|
||||
* animation's interpolator) and the evaluator used to calculate in-between values. This
|
||||
* function maps the input fraction to the appropriate keyframe interval and a fraction
|
||||
* between them and returns the interpolated value. Note that the input fraction may fall
|
||||
* outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
|
||||
* spring interpolation that might send the fraction past 1.0). We handle this situation by
|
||||
* just using the two keyframes at the appropriate end when the value is outside those bounds.
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation
|
||||
* @param evaluator The type evaluator to use when calculating the interpolated values.
|
||||
* @return The animated value.
|
||||
*/
|
||||
public Object getValue(float fraction, TypeEvaluator evaluator) {
|
||||
// TODO: special-case 2-keyframe common case
|
||||
|
||||
if (fraction <= 0f) {
|
||||
final Keyframe prevKeyframe = mKeyframes.get(0);
|
||||
final Keyframe nextKeyframe = mKeyframes.get(1);
|
||||
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
} else if (fraction >= 1f) {
|
||||
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
|
||||
final Keyframe nextKeyframe = mKeyframes.get(mNumKeyframes - 1);
|
||||
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
}
|
||||
Keyframe prevKeyframe = mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
Keyframe nextKeyframe = mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return mKeyframes.get(mNumKeyframes - 1).getValue();
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,9 @@ public final class PropertyAnimator extends Animator {
|
||||
// at a time.
|
||||
private ReentrantReadWriteLock propertyMapLock = new ReentrantReadWriteLock();
|
||||
|
||||
// Used to pass single value to varargs parameter in setter invocation
|
||||
private Object[] mTmpValueArray = new Object[1];
|
||||
|
||||
|
||||
/**
|
||||
* Sets the name of the property that will be animated. This name is used to derive
|
||||
@@ -271,6 +274,33 @@ public final class PropertyAnimator extends Animator {
|
||||
mPropertyName = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes <code>Keyframe</code>s. When this constructor
|
||||
* is called, the system expects to find a setter for <code>propertyName</code> on
|
||||
* the target object that takes a value of the same type as that returned from
|
||||
* {@link Keyframe#getType()}.
|
||||
* .
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public function on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the name of the property passed in as the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property on the <code>target</code> object
|
||||
* that will be animated. Given this name, the constructor will search for a
|
||||
* setter on the target object with the name <code>setPropertyName</code>. For example,
|
||||
* if the constructor is called with <code>propertyName = "foo"</code>, then the
|
||||
* target object should have a setter function with the name <code>setFoo()</code>.
|
||||
* @param keyframes The set of keyframes that define the times and values for the animation.
|
||||
* These keyframes should be ordered in increasing time value, should have a starting
|
||||
* keyframe with a fraction of 0 and and ending keyframe with a fraction of 1.
|
||||
*/
|
||||
public PropertyAnimator(int duration, Object target, String propertyName,
|
||||
Keyframe...keyframes) {
|
||||
super(duration, keyframes);
|
||||
mTarget = target;
|
||||
mPropertyName = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called immediately before processing the first animation
|
||||
* frame of an animation. If there is a nonzero <code>startDelay</code>, the
|
||||
@@ -309,7 +339,7 @@ public final class PropertyAnimator extends Animator {
|
||||
propertyMapLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
if (getValueFrom() == null || getValueTo() == null) {
|
||||
if (getKeyframes() == null && (getValueFrom() == null || getValueTo() == null)) {
|
||||
// Need to set up the getter if not set by the user, then call it
|
||||
// to get the initial values
|
||||
if (mGetter == null) {
|
||||
@@ -376,7 +406,8 @@ public final class PropertyAnimator extends Animator {
|
||||
super.animateValue(fraction);
|
||||
if (mSetter != null) {
|
||||
try {
|
||||
mSetter.invoke(mTarget, getAnimatedValue());
|
||||
mTmpValueArray[0] = getAnimatedValue();
|
||||
mSetter.invoke(mTarget, mTmpValueArray);
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.e("PropertyAnimator", e.toString());
|
||||
} catch (IllegalAccessException e) {
|
||||
|
||||
Reference in New Issue
Block a user