In my app I'm using ValueAnimator - it fades one image into another. It works perfectly but only after launching app. When I want to animate images again animator is not working. I tried do use animation.end() in onAnimationEnd listener but app crashes. I tried everything. Can you please help me ? Here's my method to start animation
private void animate() {
if(animator != null)
animator.end();
animator = ValueAnimator.ofFloat(0f, 1f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mPackOneSecond.setAlpha((Float) animation.getAnimatedValue());
mPackTwoSecond.setAlpha((Float) animation.getAnimatedValue());
mPackThreeSecond.setAlpha((Float) animation.getAnimatedValue());
}
});
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
startSorting(option);
}
});
animator.setDuration(2500);
animator.start();
}
Basically animate() in onCreate() works perfectly but when I want to restart it - it doesnt. Why ?
Call animator.cancel() before restart.
Related
My app plays a few seconds wav song in a loop through MediaPlayer.setLooping(true), and I want an indicator (a simple 3dp width view) that moves on the screen showing the progress, starting over at the left when the song restarts in the loop.
One way of doing this is through a HandlerTask like this:
mHandlerTask = new Runnable() {
#Override
public void run() {
if (mms != null && mms.isPlaying()) {
playprogress.setTranslationX(playprogresswidth * mms.getCurrentPosition() / duration);
}
mHandler.postDelayed(this, 500);
}
This works, but the movement is not continuous, with jumps every 500ms. Of course I can choose 50, or 5, or 1, instead 500, but then that should be quite heavy and a battery drainer.
So I implemented a ValueAnimator, like this:
ValueAnimator animation = ObjectAnimator.ofFloat(playprogress, "translationX", playprogresswidth);
animation.setRepeatCount(ValueAnimator.INFINITE);
animation.setRepeatMode(ValueAnimator.RESTART);
animation.setDuration(duration);
animation.setInterpolator(new LinearInterpolator());
animation.start();
This works, except for the fact that the MediaPlayer and the animation are not perfectly synced, and go out of sync more and more as the loop restarts. And this actually makes sense: the MediaPlayer needs some extra time for the restart.
So how I can sync both? I could not find any listener in MediaPlayer to trigger a single animation for each loop. I tried with an animation.addListener(new Animator.AnimatorListener() {...}) to try to fiddle in the duration without much luck. This is the best I got so far, with a non-repeat animation (mms is the MediaPlayer):
ValueAnimator animation = ObjectAnimator.ofFloat(playprogress, "translationX", playprogresswidth);
animation.setDuration(duration+150);
animation.setInterpolator(new LinearInterpolator());
animation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {}
#Override
public void onAnimationEnd(Animator animation) {
if (mms != null && mms.isPlaying()) {
animation.setDuration(duration - mms.getCurrentPosition() + 150);
animation.start();
}
}
#Override
public void onAnimationCancel(Animator animation) {}
#Override
public void onAnimationRepeat(Animator animation) {}
});
animation.start();
The problem with this approach is that 150: it should be device independent.
EDIT
I found a much better solution, although probably not the best one yet:
playprogress.setTranslationX(0);
ValueAnimator animation = ObjectAnimator.ofFloat(playprogress, "translationX", playprogresswidth);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(duration);
animation.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
if (mms != null && mms.isPlaying()) {
animation.setStartDelay(duration-mms.getCurrentPosition());
animation.start();
}
}
});
animation.start();
This is not the first time i found this issue.
If you play an animation at the same time than another, it stops randomly.
halfPie.post(new Runnable() {
#Override
public void run() {
ValueAnimator animator = new ValueAnimator();
animator.setObjectValues(0, 100);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
halfPie.setCenterText(String.valueOf(animation.getAnimatedValue()));
}
});
animator.setDuration(10000); // here you set the duration of the anim
animator.start();
}
});
This animation is being interrupted by halfPie animation. (Pd: It has an animation itself that shows up the entire object from invisible to visible)
Note: I know you can listen to onAnimationEnd but i want them to play together. (That doesnt mean to use AnimationSet)
Put this line in Your application tag AndroidManifest.xml file
android:hardwareAccelerated="true"
I hope this will solve your Problem
I searched a lot for how to make simple TimerAnimator like Value animator
can anyone tell me how to do it very simply
this is the one for value animator
ValueAnimator timeAnimator=ValueAnimator.ofInt(1,10);
timeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentvalue= (int) animation.getAnimatedValue();
tttt.setText(String.valueOf(currentvalue));
}
});
timeAnimator.setDuration(20000);
timeAnimator.start();
I placed an ImageView in the centre of the screen. I then wanted to animate it from the bottom to the centre. I reasoned to move it without delay out of the screen and then back the same value which would end in the centre. However, the animation makes it so the view will exit from top.
mLogoIV.animate().translationY(1000f).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mLogoIV.animate().translationY(-1000f).setDuration(3000);
}
});
use translationYBy( to animate relative to the current position
https://developer.android.com/reference/android/view/ViewPropertyAnimator.html#translationYBy(float)
mLogoIV.animate().translationYBy(1000f).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mLogoIV.animate().translationYBy(-1000f).setDuration(3000);
}
});
From the docs:
The amount to be animated by, as an offset from the current value.
vs what you are doing now:
The value to be animated to.
Use Object animator.
ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(mLogoIV, "translationY", -750, 0);
objectAnimator.setDuration(1000);
objectAnimator.start();
probably another rhetorical question.
In iOS when we set a view's (any any UIView subclass such as UIButton) alpha to 0, iOS by default disables all user interaction on that view.
I got an Android app where I animate fade out the view by:
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(buttonSelectionContainer, "alpha", 1, 0);
fadeOut.setDuration(500);
fadeOut.start();
However, I am noticing that when I tap the screen, the animation starts again, leading me to believe, in Android, even when a button alpha is set to 0, it is still tappable, is this true?
Is there a way to globally tell Android to disable user interaction for a view (and all its subviews) when its alpha is set to 0, either explicitly through using:
view.setAlpha(0.0f);
or through the ObjectAnimator like the above code block I used ?
A temporary work around for my problem would probably be to schedule this code to run after 500 ms:
// psuedocode: after 500ms
dispatch_doSomethingAfter(500)
{
myButton.setEnabled(false);
}
Not the ideal solution but might be my only solution, unless some bright Android developers out there has a better solution ?
Use addListener on your ObjectAnimator to control what happens after the animation has finished.
fadeOut.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
button.setEnabled(false);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
You can create an Animator.AnimatorListener that automatically disables the target View when the animation ends.
Declare your custom DisableViewOnEndAnimatorListener class:
public class DisableViewOnEndAnimatorListener extends AnimatorListenerAdapter {
#Override
public void onAnimationEnd(Animator animation) {
if (animation instanceof ObjectAnimator) {
final Object target = ((ObjectAnimator) animation).getTarget();
if (target instanceof View) {
((View) target).setEnabled(false);
}
}
}
}
Then, in your code:
DisableViewOnEndAnimatorListener endAnimatorListener = new DisableViewOnEndAnimatorListener();
ObjectAnimator button1FadeOut = ObjectAnimator.ofFloat(button1, "alpha", 1, 0);
button1FadeOut.setDuration(500);
button1FadeOut.addListener(endAnimatorListener);
button1FadeOut.start();
ObjectAnimator button2FadeOut = ObjectAnimator.ofFloat(button2, "alpha", 1, 0);
button2FadeOut.setDuration(500);
button2FadeOut.addListener(endAnimatorListener);
button2FadeOut.start();