Animate two values in sync on Android - android

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.

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!

Related

LinearLayout color changing (Smooth animation)

I have a LinearLayout with an initial background (lets say : #ff4455) and I want the background color to change to another value when clicking a buttonin Smooth way (FADE) .. How to do that ..
NOTE : I have FOUR buttons, each button will change the background to another color..
Use a value animator
int[] colors = new int[]{...} // create an array with colors for each button
button1.setOnClickListener(v -> updateBackgroundColor(0));
button2.setOnClickListener(v -> updateBackgroundColor(1));
button3.setOnClickListener(v -> updateBackgroundColor(2));
button4.setOnClickListener(v -> updateBackgroundColor(3));
private void updateBackgroundColor(int buttonPos) {
Drawable background = view.getBackground();
if (background instanceof ColorDrawable)
color = ((ColorDrawable) background).getColor();
int colorFrom = color == null ? defaultColor : color;
int colorTo = colors[buttonPos];
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(250); // milliseconds
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
linearLayout.setBackgroundColor((int) animator.getAnimatedValue());
}
});
colorAnimation.start();
}

Android ArgbEvaluator calculate fraction

I've a little difficult in using ArgbEvaluator object.
I want to change the color of view from one color to another color in specific duration.So I write this code,it works well.
ValueAnimator animator = ValueAnimator.ofArgb(Color.RED,Color.BLUE);
animator.setDuration(5000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (int) animation.getAnimatedValue();
view.setBackgroundColor(color);
}
});
animator.start();
But I want to use ArgbEvaluator to animate like that.
public void setColor(fraction){
int color = evaluator.evaluate(fraction,startColor,endColor);
view.setBackgroundColor(color);
}
The above setColor method will be called agian and again for specific duration(eg-5000ms).
Here is my problem.
I don't know how to calculate fraction to change color within specific duration.
I want to know the calculation formula of fraction.Thanks.

Is it possible to use one ValueAnimator or ObjectAnimator to animate multiple values in a Matrix?

I'm trying to change the X and Y scales of a Matrix object in conjunction with the changing shape of an ImageView to make it seem like the ImageView is merely a mask.
So in order to do that, I would change the scale of the ImageView's Matrix to reciprocate the changing scale of the ImageView itself.
So far, I'm using a single ValueAnimator to change the X scale of the Matrix and it worked:
final ValueAnimator xScaleIterationMatrix = ValueAnimator.ofFloat((1/xScaleSrcToDst)*initMatDstVals[0], initMatDstVals[0]);
final Matrix mat = initMatrixDst;
xScaleIterationMatrix.setDuration(animDurationCommon);
xScaleIterationMatrix.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mat.setScale((float)xScaleIterationMatrix.getAnimatedValue(), initMatDstVals[4]);
toReplace.interfaceImageView().setImageMatrix(mat);
}
});
xScaleIterationMatrix.start();
But that's just one ValueAnimator, and only one property (scaleX) of the Matrix.
I was thinking of using 2 ValueAnimators (to change the scaleX and scaleY [while setting the matrix in the latter]) to do that, but I wish for something simpler.
Can I use an ObjectAnimator for this task?
EDIT: The sample code for the 2 ValueAnimators proposal:
final ValueAnimator xScaleIterationMatrix = ValueAnimator.ofFloat(xScaleSrcToDst * initMatSrcVals[0], initMatSrcVals[0]);
xScaleIterationMatrix.setDuration(animDurationCommon);
xScaleIterationMatrix.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
resultXScale = (float)xScaleIterationMatrix.getAnimatedValue();
}
});
xScaleIterationMatrix.start();
final ValueAnimator yScaleIterationMatrix = ValueAnimator.ofFloat(yScaleSrcToDst * initMatSrcVals[4], initMatSrcVals[4]);
yScaleIterationMatrix.setDuration(animDurationCommon);
yScaleIterationMatrix.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
resultYScale = (float)yScaleIterationMatrix.getAnimatedValue();
mat.setScale(resultXScale, resultYScale);
source.interfaceImageView().setImageMatrix(mat);
}
});
yScaleIterationMatrix.start();

Android: how to use ValueAnimator

I want to do a translate animation using this following
public static void move(TextView view){
ValueAnimator va = ValueAnimator.ofFloat(0f, 3f);
int mDuration = 3000; //in millis
va.setDuration(mDuration);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
}
});
va.setRepeatCount(5);
va.start();
}
But I don't know how to use onAnimationUpdate method.
Can anyone help please?
If you really, really, really want to use ValueAnimator for animating translation of the View you can do it this way (finishing your example, assuming you meant translationX.
Bare in mind that you're animating translation from 0px to 3px, so you probably won't see much difference.
fun move(view: TextView) {
val va = ValueAnimator.ofFloat(0f, 3f)
va.duration = 3000 //in millis
va.addUpdateListener { animation -> view.translationX = animation.animatedValue as Float }
va.repeatCount = 5
va.start()
}
ValueAnimator is a great tool for making animations. Usually we have three steps:
Step 1- Create your ValueAnimator class by
ValueAnimator animator = ValueAnimator.ofFloat(start value, end value);
Step 2- Adding one update listener and overriding at least onAnimationUpdate() function
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = (float) animator.getAnimatedValue();
//this value should be used to update properties of views.
//just don't forget to run invalidate function of your views
// to redraw them.
}
});
Step 3-
animator.start();

How to animate background of ActionMode of the ActionBar?

Background
It's possible to change the background of the actionbar, and even animate between two colors, as such:
public static void animateBetweenColors(final ActionBar actionBar, final int colorFrom, final int colorTo,
final int durationInMs) {
final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
ColorDrawable colorDrawable = new ColorDrawable(colorFrom);
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
colorDrawable.setColor((Integer) animator.getAnimatedValue());
actionBar.setBackgroundDrawable(colorDrawable);
}
});
if (durationInMs >= 0)
colorAnimation.setDuration(durationInMs);
colorAnimation.start();
}
The problem
I can't find a way to get the view of the action mode, so that I could change its background on some cases (while it's showing).
What I tried
Only thing I found is a hack-y way which assumes that the id of the action mode will stay the same, and even this would work just for the view of the "done" button (the one that looks like an "V" and is actually more like "cancel").
I also found how to change it via themes, but that's not what I need, since I need to do it programmatically.
The question
How do I get the view of the actionMode, or, more precisely, how can I change its background using an animation?
How do I get the view of the actionMode, or, more precisely, how can I
change its background using an animation?
You have two choices, unfortunately neither of which involve native ActionMode APIs:
The ActionBarContextView is responsible for controlling the ActionMode
Use Resources.getIdentifier to call Activity.findViewById and pass in the ID the system uses for the ActionBarContextView
Use reflection to access to Field in ActionBarImpl
Here's an example of both:
Using Resources.getIdentifier:
private void animateActionModeViaFindViewById(int colorFrom, int colorTo, int duration) {
final int amId = getResources().getIdentifier("action_context_bar", "id", "android");
animateActionMode(findViewById(amId), colorFrom, colorTo, duration);
}
Using reflection:
private void animateActionModeViaReflection(int colorFrom, int colorTo, int duration) {
final ActionBar actionBar = getActionBar();
try {
final Field contextView = actionBar.getClass().getDeclaredField("mContextView");
animateActionMode((View) contextView.get(actionBar), colorFrom, colorTo, duration);
} catch (final Exception ignored) {
// Nothing to do
}
}
private void animateActionMode(final View actionMode, final int from, int to, int duration) {
final ValueAnimator va = ValueAnimator.ofObject(new ArgbEvaluator(), from, to);
final ColorDrawable actionModeBackground = new ColorDrawable(from);
va.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
actionModeBackground.setColor((Integer) animator.getAnimatedValue());
actionMode.setBackground(actionModeBackground);
}
});
va.setDuration(duration);
va.start();
}
Results
Here's a gif of the results animating from Color.BLACK to Color.BLUE at a duration of 2500:

Categories

Resources