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
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();
I have a "track" that goes for 50 "lenghts" and I have imageView that changes position on click for 5 "lenghts" at a time. That transition I handle with animation like this:
anima = ObjectAnimator.ofFloat(bar, "translationX", position*pix);
anima.setDuration(500);
anima.start();
At the end of the track I have another imageview that I want to detect collision with so I after animation I do this:
anima.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
if (Rect.intersects(n1, barRect)) {
//Stuff after collision
}
}
My question is, is there a way to detect collision during this animation so I stop it if collision is somewhere between those "5 lenght jumps"
Thanks to #NikolaDespotski I've managed to solve the problem by implementig onUpdateListener for my ObjectAnimator object like this:
anima.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
//Do collision detection here
}
});
I am using ViewPropertyAnimator like this:
view.animate().alpha(to).setDuration(duration);
And ValueAnimator:
ValueAnimator anim = ValueAnimator.ofInt(0, width);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
viewGroup.setMinimumWidth((Integer) valueAnimator.getAnimatedValue());
}
});
anim.setDuration(duration).start();
Sometimes I want to cancel the animation before its finished, but still apply the remaining steps immediately (as if the animation had completed). Is there a simple way to accomplish this using the APIs, or do I need to wrap the Animators in another class and handle this myself?
There are two ways of stopping a running animation.
Animator.end() // end the animation
Animator.cancel() // cancel the animation
You can use either the end() method or the cancel() method. In both cases the animation will stop and can only be restarted by calling start().
The difference between end() and cancel() is the state that the animated objects will be in after the call to the method.
When calling cancel() the animation will stop in its tracks, leaving the animated objects in an intermediate state.
When calling the end() method the animation will effectively be fast forwarded into the final state of the animation.
All objects will appear the way they would at the end of the animation.
Source: http://cogitolearning.co.uk/?p=1482
You can use an AnimatorListener for this.
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {}
#Override
public void onAnimationEnd(Animator animation) {}
#Override
public void onAnimationCancel(Animator animation) {
// Set view properties here as if the animation had completed
viewGroup.setMinimumWidth(...);
}
#Override
public void onAnimationRepeat(Animator animation) {}
});
If you don't mind using a third party library then android-transition can be used:
Import the library in Gradle:
compile 'com.github.kaichunlin.transition:core:0.9.2'
Your ViewPropertyAnimator scenario would become
TransitionAnimation animation =
ViewTransitionBuilder.transit(view).alpha(to).duration(duration).buildAnimation();
Your ValueAnimator scenario would become
final int width = <width>;
TransitionAnimation animation =
ViewTransitionBuilder.transit(viewGroup).duration(duration).addTransitionHandler(new TransitionHandler() {
#Override
public void onUpdateProgress(TransitionController controller, View target, float progress) {
target.setMinimumWidth((int) (progress*width));
}
}).buildAnimation();
Then call animation.startAnimation(); to start and animation.endAnimation(); to end the animation and applying the final state.
The advantage of this library is that that a single concept/class can be used where it would require a mix of different classes (i.e. ViewPropertyAnimator & ValueAnimator), and that the animation state/progress can be tied to UI state like how much the Drawer is being pulled out.
Am using an ObjectAnimator to translate the text in a text view similar to a stock ticker. I want to pause the ticker on press of a button. However, inspite of calling cancel()/end() on the animator object, the ticker continues to move till the end of the animation.
Have also tried explicitly clearing all animations on the underlying textView in the AnimatorListerner#onAnimCancel(). However the underlying textView doesn't seem to be associated with any animations.
Would be great if someone could point out as to what would be going wrong.
Relevant sections of code as below.
anim = ObjectAnimator.ofFloat(mTextViewTicker, "TranslationX", 0, -mSomeValue);
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationCancel(Animator animation) {
Log.d(TAG,"Animation Pause invoked");
super.onAnimationCancel(animation);
}
public void onAnimationEnd(Animator animation) {
Log.d(TAG,"Animation Ended");
((View)((ObjectAnimator)animation).getTarget()).setTranslationX(anim.getAnimatedFraction());
}
});
anim.start();
public void stopScroll() {
anim.cancel();
}
stopScroll() is invoked from a button click in the activity.
I applied an infinite animation on an ImageView to indicate a running background thread in my app. When the thread finishes, I'm able to stop the animation by using clearAnimation(), but it snaps the ImageView back to its starting position, and I'd like the current animation cycle to complete (which is designed to gracefully end in its starting position). Is there a way to do this?
Register an AnimationListener, and wait until onAnimationRepeat() to clear it. I haven't tried this, but I think it will work.
Just call setRepeatCount(0) and then listen for onAnimationEnd. See here for more details.
You can set the desirable position of your animation in the onAnimationEnd() method of your animation listener. Then, instead of going to the initial position, the View will be displayed at the coordinates you set up there.
animation = new TranslateAnimation(0, -length, 0, 0); //setup here your translation parameters
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(10);
animation.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation animation) {
animationRunning = true;
}
public void onAnimationRepeat(Animation animation) {
}
public void onAnimationEnd(Animation animation) {
animationRunning = false;
// setAnimationPositionAfterPositionChange();
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) runningText.getLayoutParams();
params.leftMargin = currentPosition; //Calculate you current position here
runningText.setLayoutParams(params);
}
});
runningText.setAnimation(animation);
If you are using animate()
you use setListener(null) to stop it the animation,
works for me.
image.animate()
.translationXBy(-width* 0.5f)
.setDuration(300)
.setStartDelay(6000)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
image.animate().rotationBy(90).setDuration(1000).setStartDelay(1).setListener(null);
}
});