Merge "Setter values can now have different type than animated values."

This commit is contained in:
George Mount
2013-10-09 20:23:19 +00:00
committed by Android (Google) Code Review
4 changed files with 186 additions and 20 deletions

View File

@@ -2521,6 +2521,7 @@ package android.animation {
method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
method public void setAutoCancel(boolean);
method public void setProperty(android.util.Property);
@@ -2538,6 +2539,8 @@ package android.animation {
method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
method public void setConverter(android.animation.TypeConverter);
method public void setEvaluator(android.animation.TypeEvaluator);
method public void setFloatValues(float...);
method public void setIntValues(int...);
@@ -2566,6 +2569,12 @@ package android.animation {
method public abstract float getInterpolation(float);
}
public abstract class TypeConverter {
ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
method public abstract V convert(T);
method public T convertBack(V);
}
public abstract interface TypeEvaluator {
method public abstract T evaluate(float, T, T);
}

View File

@@ -191,7 +191,7 @@ public final class ObjectAnimator extends ValueAnimator {
/**
* Constructs and returns an ObjectAnimator that animates between int values. A single
* value implies that that value is the one being animated to. Two values imply a starting
* value implies that that value is the one being animated to. Two values imply starting
* and ending values. More than two values imply a starting value, values to animate through
* along the way, and an ending value (these values will be distributed evenly across
* the duration of the animation).
@@ -211,7 +211,7 @@ public final class ObjectAnimator extends ValueAnimator {
/**
* Constructs and returns an ObjectAnimator that animates between int values. A single
* value implies that that value is the one being animated to. Two values imply a starting
* value implies that that value is the one being animated to. Two values imply starting
* and ending values. More than two values imply a starting value, values to animate through
* along the way, and an ending value (these values will be distributed evenly across
* the duration of the animation).
@@ -229,7 +229,7 @@ public final class ObjectAnimator extends ValueAnimator {
/**
* Constructs and returns an ObjectAnimator that animates between float values. A single
* value implies that that value is the one being animated to. Two values imply a starting
* value implies that that value is the one being animated to. Two values imply starting
* and ending values. More than two values imply a starting value, values to animate through
* along the way, and an ending value (these values will be distributed evenly across
* the duration of the animation).
@@ -249,7 +249,7 @@ public final class ObjectAnimator extends ValueAnimator {
/**
* Constructs and returns an ObjectAnimator that animates between float values. A single
* value implies that that value is the one being animated to. Two values imply a starting
* value implies that that value is the one being animated to. Two values imply starting
* and ending values. More than two values imply a starting value, values to animate through
* along the way, and an ending value (these values will be distributed evenly across
* the duration of the animation).
@@ -268,7 +268,7 @@ public final class ObjectAnimator extends ValueAnimator {
/**
* Constructs and returns an ObjectAnimator that animates between Object values. A single
* value implies that that value is the one being animated to. Two values imply a starting
* value implies that that value is the one being animated to. Two values imply starting
* and ending values. More than two values imply a starting value, values to animate through
* along the way, and an ending value (these values will be distributed evenly across
* the duration of the animation).
@@ -293,7 +293,7 @@ public final class ObjectAnimator extends ValueAnimator {
/**
* Constructs and returns an ObjectAnimator that animates between Object values. A single
* value implies that that value is the one being animated to. Two values imply a starting
* value implies that that value is the one being animated to. Two values imply starting
* and ending values. More than two values imply a starting value, values to animate through
* along the way, and an ending value (these values will be distributed evenly across
* the duration of the animation).
@@ -314,6 +314,32 @@ public final class ObjectAnimator extends ValueAnimator {
return anim;
}
/**
* Constructs and returns an ObjectAnimator that animates between Object values. A single
* value implies that that value is the one being animated to. Two values imply starting
* and ending values. More than two values imply a starting value, values to animate through
* along the way, and an ending value (these values will be distributed evenly across
* the duration of the animation). This variant supplies a <code>TypeConverter</code> to
* convert from the animated values to the type of the property. If only one value is
* supplied, the <code>TypeConverter</code> must implement
* {@link TypeConverter#convertBack(Object)} to retrieve the current value.
*
* @param target The object whose property is to be animated.
* @param property The property being animated.
* @param converter Converts the animated object to the Property type.
* @param evaluator A TypeEvaluator that will be called on each animation frame to
* provide the necessary interpolation between the Object values to derive the animated
* value.
* @param values A set of values that the animation will animate between over time.
* @return An ObjectAnimator object that is set up to animate between the given values.
*/
public static <T, V, P> ObjectAnimator ofObject(T target, Property<T, P> property,
TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, evaluator,
values);
return ofPropertyValuesHolder(target, pvh);
}
/**
* Constructs and returns an ObjectAnimator that animates between the sets of values specified
* in <code>PropertyValueHolder</code> objects. This variant should be used when animating

View File

@@ -123,6 +123,11 @@ public class PropertyValuesHolder implements Cloneable {
*/
private Object mAnimatedValue;
/**
* Converts from the source Object type to the setter Object type.
*/
private TypeConverter mConverter;
/**
* Internal utility constructor, used by the factory methods to set the property name.
* @param propertyName The name of the property for this holder.
@@ -226,6 +231,34 @@ public class PropertyValuesHolder implements Cloneable {
return pvh;
}
/**
* Constructs and returns a PropertyValuesHolder with a given property and
* set of Object values. This variant also takes a TypeEvaluator because the system
* cannot automatically interpolate between objects of unknown type. This variant also
* takes a <code>TypeConverter</code> to convert from animated values to the type
* of the property. If only one value is supplied, the <code>TypeConverter</code>
* must implement {@link TypeConverter#convertBack(Object)} to retrieve the current
* value.
*
* @param property The property being animated. Should not be null.
* @param converter Converts the animated object to the Property type.
* @param evaluator A TypeEvaluator that will be called on each animation frame to
* provide the necessary interpolation between the Object values to derive the animated
* value.
* @param values The values that the property will animate between.
* @return PropertyValuesHolder The constructed PropertyValuesHolder object.
* @see #setConverter(TypeConverter)
* @see TypeConverter
*/
public static <T, V> PropertyValuesHolder ofObject(Property<?, V> property,
TypeConverter<T, V> converter, TypeEvaluator<T> evaluator, T... values) {
PropertyValuesHolder pvh = new PropertyValuesHolder(property);
pvh.setConverter(converter);
pvh.setObjectValues(values);
pvh.setEvaluator(evaluator);
return pvh;
}
/**
* Constructs and returns a PropertyValuesHolder object with the specified property name and set
* of values. These values can be of any type, but the type should be consistent so that
@@ -360,6 +393,14 @@ public class PropertyValuesHolder implements Cloneable {
mKeyframeSet = KeyframeSet.ofObject(values);
}
/**
* Sets the converter to convert from the values type to the setter's parameter type.
* @param converter The converter to use to convert values.
*/
public void setConverter(TypeConverter converter) {
mConverter = converter;
}
/**
* Determine the setter or getter function using the JavaBeans convention of setFoo or
* getFoo for a property named 'foo'. This function figures out what the name of the
@@ -389,22 +430,24 @@ public class PropertyValuesHolder implements Cloneable {
} else {
args = new Class[1];
Class typeVariants[];
if (mValueType.equals(Float.class)) {
if (valueType.equals(Float.class)) {
typeVariants = FLOAT_VARIANTS;
} else if (mValueType.equals(Integer.class)) {
} else if (valueType.equals(Integer.class)) {
typeVariants = INTEGER_VARIANTS;
} else if (mValueType.equals(Double.class)) {
} else if (valueType.equals(Double.class)) {
typeVariants = DOUBLE_VARIANTS;
} else {
typeVariants = new Class[1];
typeVariants[0] = mValueType;
typeVariants[0] = valueType;
}
for (Class typeVariant : typeVariants) {
args[0] = typeVariant;
try {
returnVal = targetClass.getMethod(methodName, args);
// change the value type to suit
mValueType = typeVariant;
if (mConverter == null) {
// change the value type to suit
mValueType = typeVariant;
}
return returnVal;
} catch (NoSuchMethodException e) {
// Swallow the error and keep trying other variants
@@ -415,7 +458,7 @@ public class PropertyValuesHolder implements Cloneable {
if (returnVal == null) {
Log.w("PropertyValuesHolder", "Method " +
getMethodName(prefix, mPropertyName) + "() with type " + mValueType +
getMethodName(prefix, mPropertyName) + "() with type " + valueType +
" not found on target class " + targetClass);
}
@@ -465,7 +508,8 @@ public class PropertyValuesHolder implements Cloneable {
* @param targetClass The Class on which the requested method should exist.
*/
void setupSetter(Class targetClass) {
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}
/**
@@ -489,10 +533,13 @@ public class PropertyValuesHolder implements Cloneable {
if (mProperty != null) {
// check to make sure that mProperty is on the class of target
try {
Object testValue = mProperty.get(target);
Object testValue = null;
for (Keyframe kf : mKeyframeSet.mKeyframes) {
if (!kf.hasValue()) {
kf.setValue(mProperty.get(target));
if (testValue == null) {
testValue = convertBack(mProperty.get(target));
}
kf.setValue(testValue);
}
}
return;
@@ -516,7 +563,8 @@ public class PropertyValuesHolder implements Cloneable {
}
}
try {
kf.setValue(mGetter.invoke(target));
Object value = convertBack(mGetter.invoke(target));
kf.setValue(value);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
@@ -526,6 +574,18 @@ public class PropertyValuesHolder implements Cloneable {
}
}
private Object convertBack(Object value) {
if (mConverter != null) {
value = mConverter.convertBack(value);
if (value == null) {
throw new IllegalArgumentException("Converter "
+ mConverter.getClass().getName()
+ " must implement convertBack and not return null.");
}
}
return value;
}
/**
* Utility function to set the value stored in a particular Keyframe. The value used is
* whatever the value is for the property name specified in the keyframe on the target object.
@@ -535,7 +595,8 @@ public class PropertyValuesHolder implements Cloneable {
*/
private void setupValue(Object target, Keyframe kf) {
if (mProperty != null) {
kf.setValue(mProperty.get(target));
Object value = convertBack(mProperty.get(target));
kf.setValue(value);
}
try {
if (mGetter == null) {
@@ -546,7 +607,8 @@ public class PropertyValuesHolder implements Cloneable {
return;
}
}
kf.setValue(mGetter.invoke(target));
Object value = convertBack(mGetter.invoke(target));
kf.setValue(value);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
@@ -657,7 +719,8 @@ public class PropertyValuesHolder implements Cloneable {
* @param fraction The elapsed, interpolated fraction of the animation.
*/
void calculateValue(float fraction) {
mAnimatedValue = mKeyframeSet.getValue(fraction);
Object value = mKeyframeSet.getValue(fraction);
mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}
/**

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2013 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;
/**
* Abstract base class used convert type T to another type V. This
* is necessary when the value types of in animation are different
* from the property type.
* @see PropertyValuesHolder#setConverter(TypeConverter)
*/
public abstract class TypeConverter<T, V> {
private Class<T> mFromClass;
private Class<V> mToClass;
public TypeConverter(Class<T> fromClass, Class<V> toClass) {
mFromClass = fromClass;
mToClass = toClass;
}
/**
* Returns the target converted type. Used by the animation system to determine
* the proper setter function to call.
* @return The Class to convert the input to.
*/
Class<V> getTargetType() {
return mToClass;
}
/**
* Returns the source conversion type.
*/
Class<T> getSourceType() {
return mFromClass;
}
/**
* Converts a value from one type to another.
* @param value The Object to convert.
* @return A value of type V, converted from <code>value</code>.
*/
public abstract V convert(T value);
/**
* Does a conversion from the target type back to the source type. The subclass
* must implement this when a TypeConverter is used in animations and current
* values will need to be read for an animation. By default, this will return null,
* indicating that back-conversion is not supported.
* @param value The Object to convert.
* @return A value of type T, converted from <code>value</code>.
*/
public T convertBack(V value) {
return null;
}
}