Android: how to use ValueAnimator - android

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();

Related

Animate TextView to increase double value and stop at some point?

I have a TextView showing double value. Double value is transferred from API response, and I want to add animation. I want to if, for example, the double value is 2.3, I want text View to increase shown number by 0.0 until 2.3, so it would be 0.1-0.2-0.3... etc. How can I do this? I have seen examples with Value Animator but they only work with integers. Ps. my code it's in Kotlin.
public void animateTextView(float initialValue, float finalValue, final TextView textview) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(initialValue, finalValue);
valueAnimator.setDuration(1500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
textview.setText(valueAnimator.getAnimatedValue().toString());
}
});
valueAnimator.start();
}

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();

FloatingActionButton backgroundTint animation

I'd like to animate the backgroundTint value (and ideally the alpha value too) of a FloatingActionButton, so that the FAB background color continuously switches between two colors.
My noob approach would be to use a timer that calls a function that updates this property when it fires. I'm sure there's a better way of doing this?
I got this to work using ObjectAnimator as suggested by #MH. above, but I had to override the onAnimationUpdate() callback:
final ValueAnimator animator = ValueAnimator.ofInt(Color.rgb(0, 121, 107), Color.rgb(226, 143, 34));
animator.setDuration(2000L);
animator.setEvaluator(new ArgbEvaluator());
animator.setInterpolator(new DecelerateInterpolator(2));
animator.addUpdateListener(new ObjectAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
fab.setBackgroundTintList(ColorStateList.valueOf(animatedValue));
}
});
animator.start();

Android - Animate margin / change position of multiple views at once

I have a RelativeLayout with 4 Button side by side. On certain event I wish to change position / Change margin of all four Button with animation.
I am currently doing it with following code
final RelativeLayout.MarginLayoutParams params1 = (RelativeLayout.MarginLayoutParams) button1.getLayoutParams();
final RelativeLayout.MarginLayoutParams params2 = (RelativeLayout.MarginLayoutParams) button2.getLayoutParams();
final RelativeLayout.MarginLayoutParams params3 = (RelativeLayout.MarginLayoutParams) button3.getLayoutParams();
final RelativeLayout.MarginLayoutParams params4 = (RelativeLayout.MarginLayoutParams) button4.getLayoutParams();
final RelativeLayout.MarginLayoutParams params5 = (RelativeLayout.MarginLayoutParams) button5.getLayoutParams();
ValueAnimator animator1 = ValueAnimator.ofInt(params1.rightMargin, (deviceWidth - availableWithForTabs + spaceForTabs));
ValueAnimator animator2 = ValueAnimator.ofInt(params2.rightMargin, dpToPx(78));
ValueAnimator animator3 = ValueAnimator.ofInt(params3.rightMargin, dpToPx(52));
ValueAnimator animator4 = ValueAnimator.ofInt(params4.rightMargin, dpToPx(26));
ValueAnimator animator5 = ValueAnimator.ofInt(params5.rightMargin, dpToPx(0));
animator5.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
params5.rightMargin = (Integer) valueAnimator.getAnimatedValue();
}
});
animator5.setDuration(150);
animator5.start();
animator4.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
params4.rightMargin = (Integer) valueAnimator.getAnimatedValue();
}
);
animator4.setDuration(150);
animator4.start();
animator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
params3.rightMargin = (Integer) valueAnimator.getAnimatedValue();
}
});
animator3.setDuration(150);
animator3.start();
animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
params2.rightMargin = (Integer) valueAnimator.getAnimatedValue();
}
});
animator2.setDuration(150);
animator2.start();
animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
params1.rightMargin = (Integer) valueAnimator.getAnimatedValue();
button1.requestLayout();
}
});
animator1.setDuration(150);
animator1.start();
I feel above code is too much to animate margin change for 5 button. Can any one tell me a better way of doing this? or what other options i have? I have to support sdk 16 +
You might want to rethink your design, using ViewPropertyAnimator could save you you a lot lines of code and is very readable/maintainable.
Using ViewPropertyAnimator is pretty simple :
Button button1 = (Button) findViewById(R.id.button1);
button1.animate()
.translationX(toX)
.translationY(toY)
.setDuration(milliseconds); // add more if you
// like (alpha, startDelay)
// check the docs for available methods
The animation always starts at the current position of the View.
For the sake of cleaner code why dont you try something like this :
Write your own Animation Method that takes a View(in your case a Button), and all the values that you need as parameters (minimal implementation of moving a view on the x and y axis) :
private void animateView(View view, float toX, float toY, int duration) {
view.animate()
.translationX(toX)
.translationY(toY)
.setDuration(duration);
}
Then you can simply call this method on your buttons to animate them individually f.e. :
animateView(button1, 5.0f, 2.5f, 150);
animateView(button2, 2.5f, 1.0f, 150);
of course 5.0f, 2.5f etc are only fictional numbers, you'd have to fill in where you want to move the Views yourself.
Extra Suggestion : It is always nice to use Interpolators to make your animation more life like f. e. :
view.animate()
.translationX(...)
.translationY(...)
.setInterpolator(new AccelerateDecelerateInterpolator())
.setDuration(...);
If this was not thorough enough or anything is unclear let me know.
UPDATE :
If you want to set a listener you can either implement the Animator.AnimatorListener Interface in your class like this :
public class yourClass extends AppCompatActivity implements Animator.AnimatorListener {...
Then you are forced to implement the following methods :
#Override
public void onAnimationEnd(Animator animation) {
// here you can call stuff that should happen when the animation ends,
// f.e. start the next animation
// the method names explain themselves
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
Then all you have to do is add another line to your animateView method :
view.animate()
...
...
.setListener(this);
Or you can do it in an anonymous inner class like this :
view.animate()
...
...
.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
}
// same methods as above ...
...
)};
Why don't you just animate the whole relative layout containing the 4 buttons.
Also I suggest to use View.animate method
public ViewPropertyAnimator animate ()
Added in API level 12
This method returns a ViewPropertyAnimator object, which can be used to animate specific properties on this View.
Returns
ViewPropertyAnimator The ViewPropertyAnimator associated with this View.

Android Simple TextView Animation

I've got a TextView that I would like to count down (3...2...1...stuff happens).
To make it a little more interesting, I want each digit to start at full opacity, and fade out to transparency.
Is there a simple way of doing this?
Try something like this:
private void countDown(final TextView tv, final int count) {
if (count == 0) {
tv.setText(""); //Note: the TextView will be visible again here.
return;
}
tv.setText(String.valueOf(count));
AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
animation.setDuration(1000);
animation.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation anim) {
countDown(tv, count - 1);
}
... //implement the other two methods
});
tv.startAnimation(animation);
}
I just typed it out, so it might not compile as is.
I've used a more conventional Android-style animation for this:
ValueAnimator animator = new ValueAnimator();
animator.setObjectValues(0, count);
animator.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
view.setText(String.valueOf(animation.getAnimatedValue()));
}
});
animator.setEvaluator(new TypeEvaluator<Integer>() {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
return Math.round((endValue - startValue) * fraction);
}
});
animator.setDuration(1000);
animator.start();
You can play with the 0 and count values to make the counter go from any number to any number, and play with the 1000 to set the duration of the entire animation.
Note that this supports Android API level 11 and above, but you can use the awesome nineoldandroids project to make it backward compatible easily.
Take a look at CountDownAnimation.
I first tried #dmon solution, but since every animation starts at the end of the previous one you end up having a delay after several calls.
So, I implemented CountDownAnimation class which uses a Handler and the postDelayed function. By default, it uses the alpha animation, but you can set any animation. You can download the project here.

Categories

Resources