Actualización de Animate ProgressBar en Android

Estoy usando una ProgressBar en mi aplicación que actualizo en el progreso de una ASyncTask. Hasta aquí todo bien. Lo que quiero hacer es animar la actualización de progreso, para que no solo “salte” al valor sino que se mueva sin problemas hacia él.

Intenté hacerlo ejecutando el siguiente código:

this.runOnUiThread(new Runnable() { @Override public void run() { while (progressBar.getProgress() < progress) { progressBar.incrementProgressBy(1); progressBar.invalidate(); try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); 

El problema es que ProgressBar no actualiza su estado hasta que finaliza su valor final (variable de progreso). Todos los estados intermedios no se muestran en la pantalla. Llamar a progressBar.invalidate () tampoco ayudó. ¿Algunas ideas? ¡Gracias!

Utilicé la animación de Android para esto:

 public class ProgressBarAnimation extends Animation{ private ProgressBar progressBar; private float from; private float to; public ProgressBarAnimation(ProgressBar progressBar, float from, float to) { super(); this.progressBar = progressBar; this.from = from; this.to = to; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); float value = from + (to - from) * interpolatedTime; progressBar.setProgress((int) value); } } 

y llámalo así:

 ProgressBarAnimation anim = new ProgressBarAnimation(progress, from, to); anim.setDuration(1000); progress.startAnimation(anim); 

Nota: si desde y hasta el valor son demasiado bajos para producir una animación suave, multiplíquelos por 100 o más. Si lo haces, no te olvides de multiplicar setMax (..) también.

Yo uso un ObjectAnimator

 private ProgressBar progreso; private ObjectAnimator progressAnimator; progreso = (ProgressBar)findViewById(R.id.progressbar1); progressAnimator = ObjectAnimator.ofFloat(progreso, "progress", 0.0f,1.0f); progressAnimator.setDuration(7000); progressAnimator.start(); 

Aquí hay una versión mejorada de la solución @Eli Konky :

 public class ProgressBarAnimation extends Animation { private ProgressBar mProgressBar; private int mTo; private int mFrom; private long mStepDuration; /** * @param fullDuration - time required to fill progress from 0% to 100% */ public ProgressBarAnimation(ProgressBar progressBar, long fullDuration) { super(); mProgressBar = progressBar; mStepDuration = fullDuration / progressBar.getMax(); } public void setProgress(int progress) { if (progress < 0) { progress = 0; } if (progress > mProgressBar.getMax()) { progress = mProgressBar.getMax(); } mTo = progress; mFrom = mProgressBar.getProgress(); setDuration(Math.abs(mTo - mFrom) * mStepDuration); mProgressBar.startAnimation(this); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float value = mFrom + (mTo - mFrom) * interpolatedTime; mProgressBar.setProgress((int) value); } } 

Y el uso:

 ProgressBarAnimation mProgressAnimation = new ProgressBarAnimation(mProgressBar, 1000); ... /* Update progress later anywhere in code: */ mProgressAnimation.setProgress(progress); 

EDITAR: Mientras mi respuesta funciona, la respuesta de Eli Konkys es mejor. Úselo.

si el hilo se ejecuta en el hilo de la interfaz de usuario, debe entregar el hilo de la interfaz de usuario para que las vistas tengan la oportunidad de actualizarse. Actualmente le dices a la barra de progreso “actualizar a 1, actualizar a 2, actualizar a 3” sin liberar nunca el hilo de la interfaz de usuario para que realmente pueda actualizarse.

La mejor forma de resolver este problema es usar Asynctask , tiene métodos nativos que se ejecutan tanto dentro como fuera del subproceso de la interfaz de usuario:

 public class MahClass extends AsyncTask { @Override protected Void doInBackground(Void... params) { while (progressBar.getProgress() < progress) { publishProgress(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Void... values) { progressBar.incrementProgressBy(1); } } 

AsyncTask puede parecer complicado al principio, pero es realmente eficiente para muchas tareas diferentes, o como se especifica en la API de Android:

"AsyncTask permite el uso adecuado y fácil de la secuencia de UI. Esta clase permite realizar operaciones en segundo plano y publicar resultados en el subproceso de la interfaz de usuario sin tener que manipular subprocesos y / o controladores".

Podría intentar usar un controlador / ejecutable en su lugar …

 private Handler h = new Handler(); private Runnable myRunnable = new Runnable() { public void run() { if (progressBar.getProgress() < progress) { progressBar.incrementProgressBy(1); progressBar.invalidate(); h.postDelayed(myRunnable, 10); //run again after 10 ms } }; //trigger runnable in your code h.postDelayed(myRunnable, 10); //don't forget to cancel runnable when you reach 100% h.removeCallbacks(myRunnable); 

Aquí hay una versión mejorada de a.ch. solución donde también puede usar la rotación para ProgressBar circular. A veces se requiere establecer un progreso constante y cambiar solo la rotación o incluso el progreso y la rotación. También es posible forzar la rotación en sentido horario o antihorario. Espero que ayude

 public class ProgressBarAnimation extends Animation { private ProgressBar progressBar; private int progressTo; private int progressFrom; private float rotationTo; private float rotationFrom; private long animationDuration; private boolean forceClockwiseRotation; private boolean forceCounterClockwiseRotation; /** * Default constructor * @param progressBar ProgressBar object * @param fullDuration - time required to change progress/rotation */ public ProgressBarAnimation(ProgressBar progressBar, long fullDuration) { super(); this.progressBar = progressBar; animationDuration = fullDuration; forceClockwiseRotation = false; forceCounterClockwiseRotation = false; } /** * Method for forcing clockwise rotation for progress bar * Method also disables forcing counter clockwise rotation * @param forceClockwiseRotation true if should force clockwise rotation for progress bar */ public void forceClockwiseRotation(boolean forceClockwiseRotation) { this.forceClockwiseRotation = forceClockwiseRotation; if (forceClockwiseRotation && forceCounterClockwiseRotation) { // Can't force counter clockwise and clockwise rotation in the same time forceCounterClockwiseRotation = false; } } /** * Method for forcing counter clockwise rotation for progress bar * Method also disables forcing clockwise rotation * @param forceCounterClockwiseRotation true if should force counter clockwise rotation for progress bar */ public void forceCounterClockwiseRotation(boolean forceCounterClockwiseRotation) { this.forceCounterClockwiseRotation = forceCounterClockwiseRotation; if (forceCounterClockwiseRotation && forceClockwiseRotation) { // Can't force counter clockwise and clockwise rotation in the same time forceClockwiseRotation = false; } } /** * Method for setting new progress and rotation * @param progress new progress * @param rotation new rotation */ public void setProgressAndRotation(int progress, float rotation) { if (progressBar != null) { // New progress must be between 0 and max if (progress < 0) { progress = 0; } if (progress > progressBar.getMax()) { progress = progressBar.getMax(); } progressTo = progress; // Rotation value should be between 0 and 360 rotationTo = rotation % 360; // Current rotation value should be between 0 and 360 if (progressBar.getRotation() < 0) { progressBar.setRotation(progressBar.getRotation() + 360); } progressBar.setRotation(progressBar.getRotation() % 360); progressFrom = progressBar.getProgress(); rotationFrom = progressBar.getRotation(); // Check for clockwise rotation if (forceClockwiseRotation && rotationTo < rotationFrom) { rotationTo += 360; } // Check for counter clockwise rotation if (forceCounterClockwiseRotation && rotationTo > rotationFrom) { rotationTo -= 360; } setDuration(animationDuration); progressBar.startAnimation(this); } } /** * Method for setting only progress for progress bar * @param progress new progress */ public void setProgressOnly(int progress) { if (progressBar != null) { setProgressAndRotation(progress, progressBar.getRotation()); } } /** * Method for setting only rotation for progress bar * @param rotation new rotation */ public void setRotationOnly(float rotation) { if (progressBar != null) { setProgressAndRotation(progressBar.getProgress(), rotation); } } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float progress = progressFrom + (progressTo - progressFrom) * interpolatedTime; float rotation = rotationFrom + (rotationTo - rotationFrom) * interpolatedTime; // Set new progress and rotation if (progressBar != null) { progressBar.setProgress((int) progress); progressBar.setRotation(rotation); } } } 

Uso:

 ProgressBarAnimation progressBarAnimation = new ProgressBarAnimation(progressBar, 1000); // Example 1 progressBarAnimation.setProgressAndRotation(newProgress, newRotation); // Example 2 progressBarAnimation.setProgressOnly(newProgress); // Example 3 progressBarAnimation.setRotationOnly(newRotation);