Ich verwende eine ProgressBar in meiner Anwendung, die ich in onProgressUpdate einer AsyncTask
aktualisiere. So weit, ist es gut.
Was ich tun möchte, ist das Fortschritts-Update zu animieren, so dass es nicht einfach auf den Wert "springt", sondern sich reibungslos darauf bewegt.
Ich habe versucht, den folgenden Code auszuführen:
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();
}
}
}
});
Das Problem ist, dass die Statusleiste ihren Status nicht aktualisiert, bis der endgültige Wert (Fortschrittsvariable) abgeschlossen ist. Alle Zustände dazwischen werden nicht auf dem Bildschirm angezeigt. Der Aufruf von progressBar.invalidate () hat auch nicht geholfen.
Irgendwelche Ideen? Vielen Dank!
Ich habe dafür Android-Animation verwendet:
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);
}
}
und nenne es so:
ProgressBarAnimation anim = new ProgressBarAnimation(progress, from, to);
anim.setDuration(1000);
progress.startAnimation(anim);
Hinweis: Wenn from und to value zu niedrig sind, um eine glatte Animation zu erzeugen, multiplizieren Sie sie einfach mit 100 oder so. Vergessen Sie dabei nicht, auch setMax (..) zu multiplizieren.
Ich benutze einen 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();
Hier ist eine verbesserte Version von @Eli Konky solution:
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);
}
}
Und Verwendung:
ProgressBarAnimation mProgressAnimation = new ProgressBarAnimation(mProgressBar, 1000);
...
/* Update progress later anywhere in code: */
mProgressAnimation.setProgress(progress);
Der einfachste Weg mit ObjectAnimator :
ObjectAnimator.ofInt(progressBar, "progress", progressValue)
.setDuration(300)
.start();
dabei ist progressValue
eine ganze Zahl im Bereich von 0-100
Sie können den Interpolator auch mit der Methode setInterpolator () ändern. Hier ist die Visualisierung verschiedener Interpolatoren: https://www.youtube.com/watch?v=6UL7PXdJ6-E
EDIT: Während meine Antwort funktioniert, ist Eli Konkys Antwort besser. Benutze es.
wenn Ihr Thread auf dem UI-Thread ausgeführt wird, muss er den UI-Thread aufgeben, damit die Ansichten aktualisiert werden können. Derzeit sagen Sie der Fortschrittsleiste "Update auf 1, Update auf 2, Update auf 3", ohne jemals den UI-Thread zu veröffentlichen, damit er tatsächlich aktualisiert werden kann.
Der beste Weg, dieses Problem zu lösen, ist die Verwendung von Asynctask . Native Methoden können sowohl auf dem UI-Thread als auch außerhalb des UI-Threads ausgeführt werden:
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 mag auf den ersten Blick kompliziert erscheinen, ist aber für viele verschiedene Aufgaben oder wie in der Android-API angegeben effizient:
"AsyncTask ermöglicht die ordnungsgemäße und einfache Verwendung des UI-Threads. Diese Klasse Ermöglicht die Durchführung von Hintergrundoperationen und die Veröffentlichung von Ergebnissen im UI -Thread, ohne Threads und/oder Handler bearbeiten zu müssen."
Sie könnten stattdessen versuchen, einen Handler/Runable zu verwenden ...
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);
Ein Kotlin-Weg, dies zu tun
import kotlinx.Android.synthetic.main.activity.*
progressBar.max = value * 100
progressBar.progress = 0
val progressAnimator = ObjectAnimator.ofInt(progressBar, "progress", progressBar.progress, progressBar.progress + 100)
progressAnimator.setDuration(7000)
progressAnimator.start()
ProgressBar().setProgress(int progress, boolean animate)
Android hat das für Sie erledigt
Hier ist eine verbesserte Version von a.ch. Lösung, bei der Sie Rotation auch für eine zirkuläre ProgressBar verwenden können. Manchmal ist es erforderlich, einen konstanten Fortschritt einzustellen und nur die Drehung oder sogar sowohl den Fortschritt als auch die Drehung zu ändern. Es ist auch möglich, eine Drehung im oder gegen den Uhrzeigersinn zu erzwingen. Ich hoffe es wird helfen.
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);
}
}
}
Verwendungszweck:
ProgressBarAnimation progressBarAnimation = new ProgressBarAnimation(progressBar, 1000);
// Example 1
progressBarAnimation.setProgressAndRotation(newProgress, newRotation);
// Example 2
progressBarAnimation.setProgressOnly(newProgress);
// Example 3
progressBarAnimation.setRotationOnly(newRotation);