diff options
| author | George Mount <mount@google.com> | 2013-11-20 15:46:58 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-11-20 15:47:00 +0000 |
| commit | 34d8519de44f301ce0b7196e248e58345d3cd35a (patch) | |
| tree | faee178c7d84aae201a117c7195509879af4cf50 /core/java | |
| parent | 7acec30ac7d5b2fba11757a2d2e3ad351be23441 (diff) | |
| parent | c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7 (diff) | |
Merge "Add animations along a Path."
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/animation/ObjectAnimator.java | 180 | ||||
| -rw-r--r-- | core/java/android/animation/PointFEvaluator.java | 83 | ||||
| -rw-r--r-- | core/java/android/animation/PropertyValuesHolder.java | 202 |
3 files changed, 458 insertions, 7 deletions
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index 3adbf082c2c3..c0ce795f16f4 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -16,6 +16,8 @@ package android.animation; +import android.graphics.Path; +import android.graphics.PointF; import android.util.Log; import android.util.Property; @@ -210,6 +212,31 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code> + * using two properties. A <code>Path</code></> animation moves in two dimensions, animating + * coordinates <code>(x, y)</code> together to follow the line. In this variation, the + * coordinates are integers that are set to separate properties designated by + * <code>xPropertyName</code> and <code>yPropertyName</code>. + * + * @param target The object whose properties are to be animated. This object should + * have public methods on it called <code>setNameX()</code> and + * <code>setNameY</code>, where <code>nameX</code> and <code>nameY</code> + * are the value of <code>xPropertyName</code> and <code>yPropertyName</code> + * parameters, respectively. + * @param xPropertyName The name of the property for the x coordinate being animated. + * @param yPropertyName The name of the property for the y coordinate being animated. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static ObjectAnimator ofInt(Object target, String xPropertyName, String yPropertyName, + Path path) { + Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, true); + PropertyValuesHolder x = PropertyValuesHolder.ofKeyframe(xPropertyName, keyframes[0]); + PropertyValuesHolder y = PropertyValuesHolder.ofKeyframe(yPropertyName, keyframes[1]); + return ofPropertyValuesHolder(target, x, y); + } + + /** * 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 starting * and ending values. More than two values imply a starting value, values to animate through @@ -228,6 +255,27 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code> + * using two properties. A <code>Path</code></> animation moves in two dimensions, animating + * coordinates <code>(x, y)</code> together to follow the line. In this variation, the + * coordinates are integers that are set to separate properties, <code>xProperty</code> and + * <code>yProperty</code>. + * + * @param target The object whose properties are to be animated. + * @param xProperty The property for the x coordinate being animated. + * @param yProperty The property for the y coordinate being animated. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty, + Property<T, Integer> yProperty, Path path) { + Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, true); + PropertyValuesHolder x = PropertyValuesHolder.ofKeyframe(xProperty, keyframes[0]); + PropertyValuesHolder y = PropertyValuesHolder.ofKeyframe(yProperty, keyframes[1]); + return ofPropertyValuesHolder(target, x, y); + } + + /** * Constructs and returns an ObjectAnimator that animates over int values for a multiple * parameters setter. Only public methods that take only int parameters are supported. * Each <code>int[]</code> contains a complete set of parameters to the setter method. @@ -249,6 +297,26 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates the target using a multi-int setter + * along the given <code>Path</code>. A <code>Path</code></> animation moves in two dimensions, + * animating coordinates <code>(x, y)</code> together to follow the line. In this variation, the + * coordinates are integer x and y coordinates used in the first and second parameter of the + * setter, respectively. + * + * @param target The object whose property is to be animated. This object may + * have a public method on it called <code>setName()</code>, where <code>name</code> is + * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also + * be the case-sensitive complete name of the public setter method. + * @param propertyName The name of the property being animated or the name of the setter method. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static ObjectAnimator ofMultiInt(Object target, String propertyName, Path path) { + PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, path); + return ofPropertyValuesHolder(target, pvh); + } + + /** * Constructs and returns an ObjectAnimator that animates over values for a multiple int * parameters setter. Only public methods that take only int parameters are supported. * <p>At least two values must be provided, a start and end. More than two @@ -258,7 +326,7 @@ public final class ObjectAnimator extends ValueAnimator { * @param target The object whose property is to be animated. This object may * have a public method on it called <code>setName()</code>, where <code>name</code> is * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also - * be the complete name of the public method. + * be the case-sensitive complete name of the public setter method. * @param propertyName The name of the property being animated or the name of the setter method. * @param converter Converts T objects into int parameters for the multi-value setter. * @param evaluator A TypeEvaluator that will be called on each animation frame to @@ -334,6 +402,31 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code> + * using two properties. A <code>Path</code></> animation moves in two dimensions, animating + * coordinates <code>(x, y)</code> together to follow the line. In this variation, the + * coordinates are floats that are set to separate properties designated by + * <code>xPropertyName</code> and <code>yPropertyName</code>. + * + * @param target The object whose properties are to be animated. This object should + * have public methods on it called <code>setNameX()</code> and + * <code>setNameY</code>, where <code>nameX</code> and <code>nameY</code> + * are the value of the <code>xPropertyName</code> and <code>yPropertyName</code> + * parameters, respectively. + * @param xPropertyName The name of the property for the x coordinate being animated. + * @param yPropertyName The name of the property for the y coordinate being animated. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static ObjectAnimator ofFloat(Object target, String xPropertyName, String yPropertyName, + Path path) { + Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, false); + PropertyValuesHolder x = PropertyValuesHolder.ofKeyframe(xPropertyName, keyframes[0]); + PropertyValuesHolder y = PropertyValuesHolder.ofKeyframe(yPropertyName, keyframes[1]); + return ofPropertyValuesHolder(target, x, y); + } + + /** * 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 starting * and ending values. More than two values imply a starting value, values to animate through @@ -353,6 +446,24 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code> + * using two properties. A <code>Path</code></> animation moves in two dimensions, animating + * coordinates <code>(x, y)</code> together to follow the line. In this variation, the + * coordinates are floats that are set to separate properties, <code>xProperty</code> and + * <code>yProperty</code>. + * + * @param target The object whose properties are to be animated. + * @param xProperty The property for the x coordinate being animated. + * @param yProperty The property for the y coordinate being animated. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty, + Property<T, Float> yProperty, Path path) { + return ofFloat(target, xProperty.getName(), yProperty.getName(), path); + } + + /** * Constructs and returns an ObjectAnimator that animates over float values for a multiple * parameters setter. Only public methods that take only float parameters are supported. * Each <code>float[]</code> contains a complete set of parameters to the setter method. @@ -363,7 +474,7 @@ public final class ObjectAnimator extends ValueAnimator { * @param target The object whose property is to be animated. This object may * have a public method on it called <code>setName()</code>, where <code>name</code> is * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also - * be the complete name of the public method. + * be the case-sensitive complete name of the public setter method. * @param propertyName The name of the property being animated or the name of the setter method. * @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. @@ -375,6 +486,26 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates the target using a multi-float setter + * along the given <code>Path</code>. A <code>Path</code></> animation moves in two dimensions, + * animating coordinates <code>(x, y)</code> together to follow the line. In this variation, the + * coordinates are float x and y coordinates used in the first and second parameter of the + * setter, respectively. + * + * @param target The object whose property is to be animated. This object may + * have a public method on it called <code>setName()</code>, where <code>name</code> is + * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also + * be the case-sensitive complete name of the public setter method. + * @param propertyName The name of the property being animated or the name of the setter method. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static ObjectAnimator ofMultiFloat(Object target, String propertyName, Path path) { + PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, path); + return ofPropertyValuesHolder(target, pvh); + } + + /** * Constructs and returns an ObjectAnimator that animates over values for a multiple float * parameters setter. Only public methods that take only float parameters are supported. * <p>At least two values must be provided, a start and end. More than two @@ -426,6 +557,30 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates a property along a <code>Path</code>. + * A <code>Path</code></> animation moves in two dimensions, animating coordinates + * <code>(x, y)</code> together to follow the line. This variant animates the coordinates + * in a <code>PointF</code> to follow the <code>Path</code>. If the <code>Property</code> + * associated with <code>propertyName</code> uses a type other than <code>PointF</code>, + * <code>converter</code> can be used to change from <code>PointF</code> to the type + * associated with the <code>Property</code>. + * + * @param target The object whose property is to be animated. This object should + * have a public method on it called <code>setName()</code>, where <code>name</code> is + * the value of the <code>propertyName</code> parameter. + * @param propertyName The name of the property being animated. + * @param converter Converts a PointF to the type associated with the setter. May be + * null if conversion is unnecessary. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static ObjectAnimator ofObject(Object target, String propertyName, + TypeConverter<PointF, ?> converter, Path path) { + PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(propertyName, converter, path); + return ofPropertyValuesHolder(target, pvh); + } + + /** * 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 @@ -475,6 +630,27 @@ public final class ObjectAnimator extends ValueAnimator { } /** + * Constructs and returns an ObjectAnimator that animates a property along a <code>Path</code>. + * A <code>Path</code></> animation moves in two dimensions, animating coordinates + * <code>(x, y)</code> together to follow the line. This variant animates the coordinates + * in a <code>PointF</code> to follow the <code>Path</code>. If <code>property</code> + * uses a type other than <code>PointF</code>, <code>converter</code> can be used to change + * from <code>PointF</code> to the type associated with the <code>Property</code>. + * + * @param target The object whose property is to be animated. + * @param property The property being animated. Should not be null. + * @param converter Converts a PointF to the type associated with the setter. May be + * null if conversion is unnecessary. + * @param path The <code>Path</code> to animate values along. + * @return An ObjectAnimator object that is set up to animate along <code>path</code>. + */ + public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property, + TypeConverter<PointF, V> converter, Path path) { + PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, path); + 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 * several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows diff --git a/core/java/android/animation/PointFEvaluator.java b/core/java/android/animation/PointFEvaluator.java new file mode 100644 index 000000000000..91d501fcf6a9 --- /dev/null +++ b/core/java/android/animation/PointFEvaluator.java @@ -0,0 +1,83 @@ +/* + * 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; + +import android.graphics.PointF; + +/** + * This evaluator can be used to perform type interpolation between <code>PointF</code> values. + */ +public class PointFEvaluator implements TypeEvaluator<PointF> { + + /** + * When null, a new PointF is returned on every evaluate call. When non-null, + * mPoint will be modified and returned on every evaluate. + */ + private PointF mPoint; + + /** + * Construct a PointFEvaluator that returns a new PointF on every evaluate call. + * To avoid creating an object for each evaluate call, + * {@link PointFEvaluator#PointFEvaluator(android.graphics.PointF)} should be used + * whenever possible. + */ + public PointFEvaluator() { + } + + /** + * Constructs a PointFEvaluator that modifies and returns <code>reuse</code> + * in {@link #evaluate(float, android.graphics.PointF, android.graphics.PointF)} calls. + * The value returned from + * {@link #evaluate(float, android.graphics.PointF, android.graphics.PointF)} should + * not be cached because it will change over time as the object is reused on each + * call. + * + * @param reuse A PointF to be modified and returned by evaluate. + */ + public PointFEvaluator(PointF reuse) { + mPoint = reuse; + } + + /** + * This function returns the result of linearly interpolating the start and + * end PointF values, with <code>fraction</code> representing the proportion + * between the start and end values. The calculation is a simple parametric + * calculation on each of the separate components in the PointF objects + * (x, y). + * + * <p>If {@link #PointFEvaluator(android.graphics.PointF)} was used to construct + * this PointFEvaluator, the object returned will be the <code>reuse</code> + * passed into the constructor.</p> + * + * @param fraction The fraction from the starting to the ending values + * @param startValue The start PointF + * @param endValue The end PointF + * @return A linear interpolation between the start and end values, given the + * <code>fraction</code> parameter. + */ + @Override + public PointF evaluate(float fraction, PointF startValue, PointF endValue) { + float x = startValue.x + (fraction * (endValue.x - startValue.x)); + float y = startValue.y + (fraction * (endValue.y - startValue.y)); + + if (mPoint != null) { + mPoint.set(x, y); + return mPoint; + } else { + return new PointF(x, y); + } + } +} diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index c291970af952..1b028e0aab05 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -16,6 +16,9 @@ package android.animation; +import android.graphics.Path; +import android.graphics.PointF; +import android.util.FloatMath; import android.util.FloatProperty; import android.util.IntProperty; import android.util.Log; @@ -176,8 +179,8 @@ public class PropertyValuesHolder implements Cloneable { * start, through all intermediate values to the end value. When used with ObjectAnimator, * the elements of the array represent the parameters of the setter function. * - * @param propertyName The name of the property being animated. Can also be the name of the - * entire setter method. Should not be null. + * @param propertyName The name of the property being animated. Can also be the + * case-sensitive name of the entire setter method. Should not be null. * @param values The values that the property will animate between. * @return PropertyValuesHolder The constructed PropertyValuesHolder object. * @see IntArrayEvaluator#IntArrayEvaluator(int[]) @@ -204,6 +207,26 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Constructs and returns a PropertyValuesHolder with a given property name to use + * as a multi-int setter. The values are animated along the path, with the first + * parameter of the setter set to the x coordinate and the second set to the y coordinate. + * + * @param propertyName The name of the property being animated. Can also be the + * case-sensitive name of the entire setter method. Should not be null. + * The setter must take exactly two <code>int</code> parameters. + * @param path The Path along which the values should be animated. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + * @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...) + */ + public static PropertyValuesHolder ofMultiInt(String propertyName, Path path) { + Keyframe[] keyframes = createKeyframes(path); + KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(keyframes); + TypeEvaluator<PointF> evaluator = new PointFEvaluator(new PointF()); + PointFToIntArray converter = new PointFToIntArray(); + return new MultiIntValuesHolder(propertyName, converter, evaluator, keyframeSet); + } + + /** * Constructs and returns a PropertyValuesHolder with a given property and * set of Object values for use with ObjectAnimator multi-value setters. The Object * values are converted to <code>int[]</code> using the converter. @@ -276,8 +299,8 @@ public class PropertyValuesHolder implements Cloneable { * start, through all intermediate values to the end value. When used with ObjectAnimator, * the elements of the array represent the parameters of the setter function. * - * @param propertyName The name of the property being animated. Can also be the name of the - * entire setter method. Should not be null. + * @param propertyName The name of the property being animated. Can also be the + * case-sensitive name of the entire setter method. Should not be null. * @param values The values that the property will animate between. * @return PropertyValuesHolder The constructed PropertyValuesHolder object. * @see FloatArrayEvaluator#FloatArrayEvaluator(float[]) @@ -304,6 +327,26 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Constructs and returns a PropertyValuesHolder with a given property name to use + * as a multi-float setter. The values are animated along the path, with the first + * parameter of the setter set to the x coordinate and the second set to the y coordinate. + * + * @param propertyName The name of the property being animated. Can also be the + * case-sensitive name of the entire setter method. Should not be null. + * The setter must take exactly two <code>float</code> parameters. + * @param path The Path along which the values should be animated. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + * @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...) + */ + public static PropertyValuesHolder ofMultiFloat(String propertyName, Path path) { + Keyframe[] keyframes = createKeyframes(path); + KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(keyframes); + TypeEvaluator<PointF> evaluator = new PointFEvaluator(new PointF()); + PointFToFloatArray converter = new PointFToFloatArray(); + return new MultiFloatValuesHolder(propertyName, converter, evaluator, keyframeSet); + } + + /** * Constructs and returns a PropertyValuesHolder with a given property and * set of Object values for use with ObjectAnimator multi-value setters. The Object * values are converted to <code>float[]</code> using the converter. @@ -367,6 +410,27 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Constructs and returns a PropertyValuesHolder with a given property name and + * a Path along which the values should be animated. This variant supports a + * <code>TypeConverter</code> to convert from <code>PointF</code> to the target + * type. + * + * @param propertyName The name of the property being animated. + * @param converter Converts a PointF to the type associated with the setter. May be + * null if conversion is unnecessary. + * @param path The Path along which the values should be animated. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static PropertyValuesHolder ofObject(String propertyName, + TypeConverter<PointF, ?> converter, Path path) { + Keyframe[] keyframes = createKeyframes(path); + PropertyValuesHolder pvh = ofKeyframe(propertyName, keyframes); + pvh.setEvaluator(new PointFEvaluator(new PointF())); + pvh.setConverter(converter); + 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. @@ -415,6 +479,27 @@ public class PropertyValuesHolder implements Cloneable { } /** + * Constructs and returns a PropertyValuesHolder with a given property and + * a Path along which the values should be animated. This variant supports a + * <code>TypeConverter</code> to convert from <code>PointF</code> to the target + * type. + * + * @param property The property being animated. Should not be null. + * @param converter Converts a PointF to the type associated with the setter. May be + * null if conversion is unnecessary. + * @param path The Path along which the values should be animated. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static <V> PropertyValuesHolder ofObject(Property<?, V> property, + TypeConverter<PointF, V> converter, Path path) { + Keyframe[] keyframes = createKeyframes(path); + PropertyValuesHolder pvh = ofKeyframe(property, keyframes); + pvh.setEvaluator(new PointFEvaluator(new PointF())); + pvh.setConverter(converter); + 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 * an appropriate {@link android.animation.TypeEvaluator} can be found that matches @@ -1439,6 +1524,113 @@ public class PropertyValuesHolder implements Cloneable { } } + /* Path interpolation relies on approximating the Path as a series of line segments. + The line segments are recursively divided until there is less than 1/2 pixel error + between the lines and the curve. Each point of the line segment is converted + to a Keyframe and a linear interpolation between Keyframes creates a good approximation + of the curve. + + The fraction for each Keyframe is the length along the Path to the point, divided by + the total Path length. Two points may have the same fraction in the case of a move + command causing a disjoint Path. + + The value for each Keyframe is either the point as a PointF or one of the x or y + coordinates as an int or float. In the latter case, two Keyframes are generated for + each point that have the same fraction. */ + + /** + * Returns separate Keyframes arrays for the x and y coordinates along a Path. If + * isInt is true, the Keyframes will be IntKeyframes, otherwise they will be FloatKeyframes. + * The element at index 0 are the x coordinate Keyframes and element at index 1 are the + * y coordinate Keyframes. The returned values can be linearly interpolated and get less + * than 1/2 pixel error. + */ + static Keyframe[][] createKeyframes(Path path, boolean isInt) { + if (path == null || path.isEmpty()) { + throw new IllegalArgumentException("The path must not be null or empty"); + } + float[] pointComponents = path.approximate(0.5f); + + int numPoints = pointComponents.length / 3; + + Keyframe[][] keyframes = new Keyframe[2][]; + keyframes[0] = new Keyframe[numPoints]; + keyframes[1] = new Keyframe[numPoints]; + int componentIndex = 0; + for (int i = 0; i < numPoints; i++) { + float fraction = pointComponents[componentIndex++]; + float x = pointComponents[componentIndex++]; + float y = pointComponents[componentIndex++]; + if (isInt) { + keyframes[0][i] = Keyframe.ofInt(fraction, Math.round(x)); + keyframes[1][i] = Keyframe.ofInt(fraction, Math.round(y)); + } else { + keyframes[0][i] = Keyframe.ofFloat(fraction, x); + keyframes[1][i] = Keyframe.ofFloat(fraction, y); + } + } + return keyframes; + } + + /** + * Returns PointF Keyframes for a Path. The resulting points can be linearly interpolated + * with less than 1/2 pixel in error. + */ + private static Keyframe[] createKeyframes(Path path) { + if (path == null || path.isEmpty()) { + throw new IllegalArgumentException("The path must not be null or empty"); + } + float[] pointComponents = path.approximate(0.5f); + + int numPoints = pointComponents.length / 3; + + Keyframe[] keyframes = new Keyframe[numPoints]; + int componentIndex = 0; + for (int i = 0; i < numPoints; i++) { + float fraction = pointComponents[componentIndex++]; + float x = pointComponents[componentIndex++]; + float y = pointComponents[componentIndex++]; + keyframes[i] = Keyframe.ofObject(fraction, new PointF(x, y)); + } + return keyframes; + } + + /** + * Convert from PointF to float[] for multi-float setters along a Path. + */ + private static class PointFToFloatArray extends TypeConverter<PointF, float[]> { + private float[] mCoordinates = new float[2]; + + public PointFToFloatArray() { + super(PointF.class, float[].class); + } + + @Override + public float[] convert(PointF value) { + mCoordinates[0] = value.x; + mCoordinates[1] = value.y; + return mCoordinates; + } + }; + + /** + * Convert from PointF to int[] for multi-int setters along a Path. + */ + private static class PointFToIntArray extends TypeConverter<PointF, int[]> { + private int[] mCoordinates = new int[2]; + + public PointFToIntArray() { + super(PointF.class, int[].class); + } + + @Override + public int[] convert(PointF value) { + mCoordinates[0] = Math.round(value.x); + mCoordinates[1] = Math.round(value.y); + return mCoordinates; + } + }; + native static private int nGetIntMethod(Class targetClass, String methodName); native static private int nGetFloatMethod(Class targetClass, String methodName); native static private int nGetMultipleIntMethod(Class targetClass, String methodName, @@ -1456,4 +1648,4 @@ public class PropertyValuesHolder implements Cloneable { native static private void nCallFourFloatMethod(Object target, int methodID, float arg1, float arg2, float arg3, float arg4); native static private void nCallMultipleFloatMethod(Object target, int methodID, float[] args); -}
\ No newline at end of file +} |
