Reputation: 4062
In general, I'm trying to animate on an array of int values, unlike the typical case where you are just animating an int or float from one number to another.
To be specific, I'm trying to animate the int [] of colors on a GradientDrawable object.
GradientDrawable has a property named "setColors(int []) " in which I set 2 colors, the starting color and ending color, which make up a whole gradient.
I want to animate from one combination of colors towards another. If it were a solid color, I could already do this, like the following:
Integer colorFrom = getResources().getColor(R.color.red);
Integer colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
textView.setBackgroundColor((Integer)animator.getAnimatedValue());
}
});
colorAnimation.start();
So, I need something like this:
//Define 2 starting colors
Integer colorFrom1 = getResources().getColor(R.color.red);
Integer colorFrom2 = getResources().getColor(R.color.darkred);
int[] startColors = new int[] {colorFrom1, colorFrom2};
//Define 2 ending colors
Integer colorTo1 = getResources().getColor(R.color.blue);
Integer colorTo2 = getResources().getColor(R.color.darkblue);
int[] endColors = new int[] {colorTo1, colorTo2};
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), startColors, endColors);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
gradientView.setColors((Integer)animator.getAnimatedValues()[0] , (Integer)animator.getAnimatedValues()[1]);
}
});
colorAnimation.start();
Obvioulsy that code won't exist because there is no getAnimatedValues() method returning an array and furthermore there is no ValueAnimator.ofObject method which accepts an array as a start and end values.
Any ideas?
My only idea now is to run two animators in parallel, each animating one dimension of the gradient, and each setting only half of the array accepted by gradientDrawable.setColors().... but boyyyy that would be nearly unacceptably inefficient and possibly dangerously out-of-sync.
Upvotes: 2
Views: 1334
Reputation: 619
How about this?
public class ArgbArrayEvaluator implements TypeEvaluator<Integer[]> {
ArgbEvaluator evaluator = new ArgbEvaluator();
public Integer[] evaluate(float fraction, Integer[] startValues, Integer[] endValues) {
if(startValues.length != endValues.length) throw new ArrayIndexOutOfBoundsException();
Integer[] values = new Integer[startValues.length];
for(int = 0;i<startValues.length;i++) {
values[i] = (Integer) evaluator.evaluate(fraction,startValues[i],endValues[i]);
}
return values;
}
}
Then do
/* Make sure startColors and endColors are Integer[] not int[] */
final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbArrayEvaluator(),startColors,endColors);
Your listener code:
public void onAnimationUpdate(ValueAnimator animator) {
Integer[] values = (Integer[]) animator.getAnimatedValue();
gradientView.setColors(values[0],values[1]);
}
Alternatively, with ObjectAnimator
final ObjectAnimator colorAnimation = ObjectAnimator.ofMultiInt(gradientView,"colors",null, new ArgbArrayEvaluator(), startColors,endColors);
Also, in the ValueAnimator documentation for the start() method it says:
The animation started by calling this method will be run on the thread that called this method. This thread should have a Looper on it (a runtime exception will be thrown if this is not the case). Also, if the animation will animate properties of objects in the view hierarchy, then the calling thread should be the UI thread for that view hierarchy.
So I would use the following if you're not already in the UI thread.
runOnUiThread(new Runnable() {
public void run() {
colorAnimation.start();
}
});
I think it'll work!
Upvotes: 2