I have an ImageView that I use to show progress via an AnimationDrawable. When I want to show my progress spinner, I do this:
animDrawable.start();
ObjectAnimator.ofFloat(view, "alpha", 1.0f).setDuration(300).start();
When I want to hide the spinner, I do this:
ObjectAnimator.ofFloat(view, "alpha", 0.0f).setDuration(300).start();
animDrawable.stop();
However, this has the effect that the animation stops immediately. I would like it to stop only after the ObjectAnimator has completely faded to 0.0 alpha. Is there a way I can setup something along the lines of an "AnimationCompleted" callback?
The more modern way of doing this is to use the ViewPropertyAnimator:
view.animate()
.alpha(0f)
.withEndAction(new Runnable() {
#Override
public void run() {
// Do something.
}
})
.start();
Or, if you're using RetroLambda:
view.animate()
.alpha(0f)
.withEndAction(() -> {
// Do something.
})
.start();
To your original question about the ObjectAnimator object you can set up an Animator.AnimatorListener object which defines several animation state callbacks. You want to override public void onAnimationEnd(Animator animation)
animation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
Toast.makeText(VideoEditorActivity.this, "animation ended", Toast.LENGTH_LONG).show();
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
With androidx you can use doOnEnd method which invoked when the animation has ended
val anim = ObjectAnimator.ofFloat(eva_image, View.TRANSLATION_Y, 0f, 500f)
anim.setDuration(500)
anim.doOnEnd { Toast.makeText(this, "Anim End", Toast.LENGTH_SHORT).show() }
anim.start()
You could also look into postOnAnimation(Runnable)
Link to Docs: postOnAnimation(java.lang.Runnable)
Related
I've set an Animation on ProgressBar in click event in Adapter
ObjectAnimator animation = ObjectAnimator.ofInt(holder.progressbar, "progress", 0, 100);
animation.setDuration(PROGRESS_TIME);
animation.setInterpolator(new DecelerateInterpolator());
animation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
Toast.makeText(context,"HELL_Start",Toast.LENGTH_SHORT).show();
}
#Override
public void onAnimationEnd(Animator animator) {
//do something when the countdown is complete
Toast.makeText(context,"HELL_OFF_END",Toast.LENGTH_SHORT).show();
}
#Override
public void onAnimationCancel(Animator animator) {
Toast.makeText(context,"HELL_OFF_Cancel",Toast.LENGTH_SHORT).show();
}
#Override
public void onAnimationRepeat(Animator animator) { }
});
animation.start();
I'm trying to get Animation (when list item values get changed) from the ProgressBar by using
AlphaAnimation animation = (AlphaAnimation)mProgressBar.getAnimation();
but it is returning null
You can set the animator object as the associated view's tag.
holder.progressbar.setTag(animation);
Than retrieve it later:
ObjectAnimator animator = (ObjectAnimator) holder.progressBar.getTag();
// Do something with animator
i use this code for animate x and y position for view
the code
v.animate().x(margin).y(0).setDuration(200).start();
how can i call method when this animation finished
i have this code also i can by it call method when finished the animate
but i cant set x and y for View
ValueAnimator varl = ValueAnimator.ofInt(from,to);
varl.setDuration(200);
varl.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
}
});
varl.addListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
// animate finish call method
}
});
varl.start();
i just thinking about make this code
v.animate().x(margin).y(0).setDuration(200).start();
inside the method onAnimationUpdate
i think its bad idea any another solution
Looks like the base class has a listener.
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0.0f);
anim.addListener(new AnimatorListener() {
...
#Override
public void onAnimationEnd(Animator animation) {
// Do something.
}
...
});
anim.setDuration(300).start();
When I swipe right on a TextView, I want to start the animation and remove it, but the TextView is being removed without the animation. Any ideas on how to fix this, and why this would not work? Thank you.
public void onSwipeRight() {
textview.animate().translationX(500).alpha(0).setDuration(150).start();
linearlayout.removeView(textview);
}
You need to wait for the animation to complete before you remove the view:
textview.animate()
.translationX(500)
.alpha(0)
.setDuration(150)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
linearlayout.removeView(textview);
}
})
.start();
Note: Since alpha(int) is deprecated you need to use:
textview.animate()
.translationX(500)
.alpha(0f) //float value
.setDuration(150)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
linearlayout.removeView(textview);
}
})
.start();
I want to vibrate a view with scaleX and scaleY, and I am doing it with this code, but the problem is that sometimes the view is not correctly reset, and it shows with the scale applied...
I want that when the animation ends, the view must be seen with its original status always
this is the code:
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.9f);
scaleX.setDuration(50);
scaleX.setRepeatCount(5);
scaleX.setRepeatMode(Animation.REVERSE);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.9f);
scaleY.setDuration(50);
scaleY.setRepeatCount(5);
scaleY.setRepeatMode(Animation.REVERSE);
set.play(scaleX).with(scaleY);
set.start();
Thanks
For ValueAnimator and ObjectAnimator can be like this a try:
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
animation.setDuration(0);
((ValueAnimator) animation).reverse();
}
});
UPDATE
On Android 7 it doesn't work.
Best way use the interpolator.
public class ReverseInterpolator implements Interpolator {
private final Interpolator delegate;
public ReverseInterpolator(Interpolator delegate){
this.delegate = delegate;
}
public ReverseInterpolator(){
this(new LinearInterpolator());
}
#Override
public float getInterpolation(float input) {
return 1 - delegate.getInterpolation(input);
}
}
In your code
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
animation.setDuration(0);
animation.setInterpolator(new ReverseInterpolator());
animation.start();
}
});
According to the docs(Property Animation):
The property animation system can animate Views on the screen by changing the actual properties in the View objects. In addition, Views also automatically call the invalidate() method to refresh the screen whenever its properties are changed.
so you can use AnimatorListener to listen the animation event, then just reset the view property you animate. let's say cancel event and scaleX property:
scaleAnimator.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationCancel(Animator animation) {
scaleView.setScaleX(0)
}
});
Hope this can help a bit.
You can add an AnimatorListener, to be notified when the animation ends:
scaleY.addListener(new AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
// TODO Restore view
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
});
Hi I am applying multiple animations to a view using AnimatorSet and ValueAnimator.
When the user touches the view, successive animations are applied to the view. I do this to have a "zooming effect" when the user is moving his fingers on the view.
The view is a custom gallery.
Here is the code for animation:
private void createAnim(final View v) {
animating = true;
if (D)
Log.i(TAG, "sarting animation");
try {
v.clearAnimation();
v.getAnimation().reset();
} catch (Exception e) {
}
set = new AnimatorSet();
set.addListener(new AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
if (D)
Log.i(TAG, "Animation ended");
animating = false;
}
#Override
public void onAnimationCancel(Animator animation) {
animating = false;
if (D)
Log.i(TAG, "Animation cancelled");
}
});
set.setDuration(100);
ValueAnimator v1 = ObjectAnimator.ofFloat(v, "scaleX", mScaleFactor);
ValueAnimator v2 = ObjectAnimator.ofFloat(v, "scaleY", mScaleFactor);
animationList.add(v1);
animationList.add(v2);
set.playTogether(v1, v2);
set.start()
}
I have an onTouchListener and on action move I successively call this method increasing or decreasing the mScaleFactor.
When the user releases the finger I would like the view to go back to previous state, I mean to erase all animations applied as if they were never applied to view. The problem is you can easily do that for one animation but for many like that I just can't find the right way. Here is what I have tried:
-Adding the animations to an ArrayList and doing animation.reverse() on each one of them with a delay of +100 added to each of them so the execute one after another but the end result just doesn't seem exactly the same as before animations.
v.clearAnimation(); only cancels the last animation
v.getAnimation().reset(); same only works for last/active animation.
Is there a method to just get the view back as it was before any animation has been started?
Thanks a lot
Reversing the effects of an AnimatorSet can be tricky simply because there is no "reverse" method. The easiest method in this case, would probably simply be another AnimatorSet that does the opposite of the original. The issue here would be is your AnimatorListener could be out of sync. If you do this way and you want to keep the boolean, then you'd have to implement it as somewhat of a semaphore.
public static class AnimatorTracker implements AnimatorListener{
int counter;
public AnimatorTracker() {
counter = 0;
}
public boolean isAnimating() {
return counter == 0;
}
#Override
public void onAnimationStart(Animator animation) {
counter++;
}
#Override
public void onAnimationRepeat(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
counter--;
}
#Override
public void onAnimationCancel(Animator animation) {
// Canceling an animation invokes onAnimationEnd, so nothing needs to be done.
}
}
Then just make the sets the same way you just did:
AnimatorTracker tracker = new AnimatorTracker(); // or make it a global reference
AnimatorSet set = new AnimatorSet();
AnimatorSet reverseSet = new AnimatorSet();
ValueAnimator v1 = ObjectAnimator.ofFloat(v, "scaleX", mScaleFactor);
ValueAnimator v2 = ObjectAnimator.ofFloat(v, "scaleY", mScaleFactor);
ValueAnimator reverseV1 = ObjectAnimator.ofFloat(v, "scaleX", 1.0f);
ValueAnimator reverseV2 = ObjectAnimator.ofFloat(v, "scaleY", 1.0f);
set.addListener(tracker);
set.setDuration(100);
set.playTogether(v1, v2);
reverseSet.addListener(tracker);
reverseSet.setDuration(100);
reverseSet.playTogether(reverseV1, reverseV2);
Call set.start() when you want to animate forward. Call reverseSet.start() when you want to animate back.