Animar la actualización de ProgressBar en Android
Estoy utilizando un ProgressBar en mi aplicación que actualizo en onProgressUpdate de un ASyncTask. Hasta aquí todo bien. Lo que quiero hacer es animar la actualización de progreso, por lo que no sólo "saltar" al valor, sino que se mueve sin problemas a ella.
He intentado hacerlo ejecutando el siguiente código:
- Barras del sistema translúcido y margen de contenido en KitKat
- Cambiar el tamaño de los diseños de forma dinámica con ViewFlipper
- Buen diseño de la interfaz de usuario: ¿Cómo manejar ListView vacío?
- Android - ¿Hay una manera de girar un brindis de 90 grados?
- Convertir imágenes png a 9 parche en Android Studio
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 terminó 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!
- Android: Añadir un fragmento a una actividad
- Cómo centrar el icono y el texto en un botón android con el ancho establecido en "fill parent"
- Android UI DPI problema - es xxxhdpi recursos necesarios?
- Cómo agregar el botón de acción flotante en la parte superior de scrollview
- Icono de barra de acciones ocultado después de que SearchView se expande
- Cómo eliminar drawableleft
- Cuadro de diálogo GUI de reconocimiento de voz personalizado de Android
- Accede a la base de datos sqlite de Android desde el PC de desarrollo
He utilizado 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 lo llaman así:
ProgressBarAnimation anim = new ProgressBarAnimation(progress, from, to); anim.setDuration(1000); progress.startAnimation(anim);
Nota: si desde y hacia el valor son demasiado bajos para producir una animación suave simplemente multiplíqueles por un 100 o así. Si lo hace, no olvide multiplicar setMax (…) también.
Utilizo 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();
Esta es 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 uso:
ProgressBarAnimation mProgressAnimation = new ProgressBarAnimation(mProgressBar, 1000); ... /* Update progress later anywhere in code: */ mProgressAnimation.setProgress(progress);
EDIT: Mientras mi respuesta funciona, respuesta de Eli Konkys es mejor. Utilícelo.
Si su hilo se ejecuta en el hilo de interfaz de usuario, debe entregar el hilo de interfaz de usuario para dar a las vistas una oportunidad para actualizar. Actualmente le indica a la barra de progreso "actualizar a 1, actualizar a 2, actualizar a 3" sin liberar nunca el hilo de interfaz de usuario para que realmente pueda actualizar.
La mejor manera de resolver este problema es utilizar Asynctask , tiene métodos nativos que se ejecutan tanto dentro como fuera del subproceso de la interfaz de usuario:
public class MahClass extends AsyncTask<Void, Void, Void> { @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 del subproceso de la interfaz de usuario. Esta clase permite realizar operaciones en segundo plano y publicar resultados en el subproceso de interfaz de usuario sin tener que manipular subprocesos y / o controladores".
Usted podría intentar utilizar un manejador / runnable 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);
Esta es una versión mejorada de a.ch. Donde también se puede utilizar la rotación para ProgressBar circular. A veces es necesario establecer un progreso constante y cambiar sólo 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);
- WebView de Android, escala de imagen para adaptarse a la pantalla
- Llamar al diálogo de Android sin que desaparezca el fondo