Make a ProgressBar update smoothly

JavaAndroidAndroid Layout

Java Problem Overview


I'm using a progress bar (in bar form). I wish to make the bar increase and decrease smoothly using an interpolator, but It's not working. This is what I have at the moment:

pb.setInterpolator(main.this, android.R.anim.bounce_interpolator);		       
pb.setProgress(pb.getProgress()+10);

Am I doing something really wrong?

Java Solutions


Solution 1 - Java

The Interpolator has to be attached to an animation and this will work only on Honeycomb or higher:

if(android.os.Build.VERSION.SDK_INT >= 11){
    // will update the "progress" propriety of seekbar until it reaches progress
    ObjectAnimator animation = ObjectAnimator.ofInt(seekbar, "progress", progress); 
    animation.setDuration(500); // 0.5 second
    animation.setInterpolator(new DecelerateInterpolator());
    animation.start();
}
else 
    seekbar.setProgress(progress); // no animation on Gingerbread or lower

If your minimum SDK is Gingerbread or lower, add:

@TargetApi(Build.VERSION_CODES.HONEYCOMB) 
// or 
@SuppressLint("NewApi") 

to your function/class.

I used a DecelerateInterpolator, but this is optional and there are others possibilities.

Solution 2 - Java

Here is a self-contained drop in solution:

import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.util.AttributeSet;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.ProgressBar;

public class AnimatingProgressBar extends ProgressBar {

	private static final Interpolator DEFAULT_INTERPOLATER = new AccelerateDecelerateInterpolator();

	private ValueAnimator animator;
	private ValueAnimator animatorSecondary;
	private boolean animate = true;

	public AnimatingProgressBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public AnimatingProgressBar(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public AnimatingProgressBar(Context context) {
		super(context);
	}

	public boolean isAnimate() {
		return animate;
	}

	public void setAnimate(boolean animate) {
		this.animate = animate;
	}

	@Override
	public synchronized void setProgress(int progress) {
		if (!animate) {
			super.setProgress(progress);
			return;
		}
		if (animator != null)
			animator.cancel();
		if (animator == null) {
			animator = ValueAnimator.ofInt(getProgress(), progress);
			animator.setInterpolator(DEFAULT_INTERPOLATER);
			animator.addUpdateListener(new AnimatorUpdateListener() {

				@Override
				public void onAnimationUpdate(ValueAnimator animation) {
					AnimatingProgressBar.super.setProgress((Integer) animation.getAnimatedValue());
				}
			});
		} else
			animator.setIntValues(getProgress(), progress);
		animator.start();

	}

	@Override
	public synchronized void setSecondaryProgress(int secondaryProgress) {
		if (!animate) {
			super.setSecondaryProgress(secondaryProgress);
			return;
		}
		if (animatorSecondary != null)
			animatorSecondary.cancel();
		if (animatorSecondary == null) {
			animatorSecondary = ValueAnimator.ofInt(getProgress(), secondaryProgress);
			animatorSecondary.setInterpolator(DEFAULT_INTERPOLATER);
			animatorSecondary.addUpdateListener(new AnimatorUpdateListener() {

				@Override
				public void onAnimationUpdate(ValueAnimator animation) {
					AnimatingProgressBar.super.setSecondaryProgress((Integer) animation
							.getAnimatedValue());
				}
			});
		} else
			animatorSecondary.setIntValues(getProgress(), secondaryProgress);
		animatorSecondary.start();
	}

	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		if (animator != null)
			animator.cancel();
		if (animatorSecondary != null)
			animatorSecondary.cancel();
	}

}

replace ProgressBar with AnimatingProgressBar in your layout

You many also change the type to AnimatingProgressBar to utilize setAnimate() to disable animation (could be useful when restoring activity state)

Solution 3 - Java

If you change progress value each time by 1 (for example from 45 to 46) you'll not see animation. Better to change progress by 100 points, for this you just need to multiply your max value to 100 and each progress value to 100 too. For example:

private void setProgressMax(ProgressBar pb, int max) {
    pb.setMax(max * 100);
}

private void setProgressAnimate(ProgressBar pb, int progressTo) 
{
    ObjectAnimator animation = ObjectAnimator.ofInt(pb, "progress", pb.getProgress(), progressTo * 100);
    animation.setDuration(500);
    animation.setInterpolator(new DecelerateInterpolator());
    animation.start();
}

Solution 4 - Java

I worked out how to do it, by using a runnable I was able to update the progress bar several times a second and so give the sliding effect. The code is below:

private Runnable SmoothIncrement = new Runnable() {
	   public void run() {
	       final long start = mStartTime;
	       long millis = SystemClock.uptimeMillis() - start;
	       
	       if(track!=increase) {
	    	   if((pb.getProgress()==100)&&(count<target)) {
		    	   pb.setProgress(0);
	    	   }
	    	   pb.incrementProgressBy(1);
	    	   track++;
		       incrementor.postAtTime(this, start + millis);
	       }
	       else {
	    	   incrementor.removeCallbacks(this);
	       }
	   }
	};

Here, 'track' keeps track of how many increments have been done, and increase is the total number of increments that should be done. I can dynamically increase the number of increments from the UI thread to give a smooth effect. The code only works for progress bars that won't need to decrease.

To run it, simply use this code:

				    mStartTime = System.currentTimeMillis();
	            	incrementor.removeCallbacks(SmoothIncrement);
	            	if(track!=0) {
	            		track -= increase;
	            	}
	            	incrementor.postDelayed(SmoothIncrement, 0);

Solution 5 - Java

I am not sure but please check it:

pb.setProgress(pb.getProgress() * 100);

Solution 6 - Java

According to documentation interpolator applies to indeterminate progress. Since you set progress I think you intend to use regular one with values. I think the best for you would be to increase maximum value of progress and go in smaller increments.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTodd DaviesView Question on Stackoverflow
Solution 1 - JavanowView Answer on Stackoverflow
Solution 2 - Javatom91136View Answer on Stackoverflow
Solution 3 - JavaPavel KataykinView Answer on Stackoverflow
Solution 4 - JavaTodd DaviesView Answer on Stackoverflow
Solution 5 - JavaNikhilView Answer on Stackoverflow
Solution 6 - JavaAlex GitelmanView Answer on Stackoverflow