AsyncTask
のonProgressUpdateで更新するアプリケーションでProgressBarを使用しています。ここまでは順調ですね。
私がやりたいのは、進行状況の更新をアニメートして、値に「ジャンプ」するだけでなく、スムーズに移動するようにすることです。
私は次のコードを実行してみました:
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();
}
}
}
});
問題は、プログレスバーが最終値(進行変数)を完了するまで状態を更新しないことです。その間のすべての状態が画面に表示されるわけではありません。 progressBar.invalidate()を呼び出しても解決しませんでした。
何か案は?ありがとう!
私はAndroidこれにアニメーションを使用しました:
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);
}
}
次のように呼び出します:
ProgressBarAnimation anim = new ProgressBarAnimation(progress, from, to);
anim.setDuration(1000);
progress.startAnimation(anim);
注:fromとtoの値が低すぎてスムーズなアニメーションを生成できない場合は、100倍ほど掛けてください。その場合は、setMax(..)も乗算することを忘れないでください。
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();
最も簡単な方法、 ObjectAnimator を使用:
ObjectAnimator.ofInt(progressBar, "progress", progressValue)
.setDuration(300)
.start();
progressValue
は0〜100の範囲内の整数です(デフォルトでは上限は100に設定されていますが、 Progressbar#setMax() メソッドで変更できます)
setInterpolator() メソッドを使用して異なる補間器を設定することにより、値の変化方法を変更することもできます。さまざまな補間器の視覚化を次に示します。 https://www.youtube.com/watch?v=6UL7PXdJ6-E
@ 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);
}
}
そして使用法:
ProgressBarAnimation mProgressAnimation = new ProgressBarAnimation(mProgressBar, 1000);
...
/* Update progress later anywhere in code: */
mProgressAnimation.setProgress(progress);
ProgressBar().setProgress(int progress, boolean animate)
Androidがそれを処理してくれます
これを行うKotlinの方法
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()
編集:私の答えはうまくいきますが、Eli Konkysの答えはより良いです。それを使用します。
スレッドがUIスレッドで実行される場合、ビューに更新の機会を与えるためにUIスレッドを放棄する必要があります。現在、UIスレッドを実際に更新できるようにリリースすることなく、プログレスバーに「1に更新、2に更新、3に更新」と伝えます。
この問題を解決する最良の方法は、 Asynctask を使用することです。UIスレッドのオンとオフの両方で実行するネイティブメソッドがあります。
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は最初は複雑に見えるかもしれませんが、多くの異なるタスクに対して、またはAndroid APIで指定されているように)本当に効率的です。
「AsyncTaskを使用すると、UIスレッドを適切かつ簡単に使用できます。このクラスを使用すると、スレッドやハンドラーを操作しなくても、バックグラウンド操作を実行し、UIスレッドで結果を公開できます。」
代わりにハンドラー/ランナブルを使用してみてください...
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);
これはa.chの改良版です。円形のProgressBarの回転も使用できるソリューション。一定の進行状況を設定し、回転のみ、または進行と回転の両方を変更する必要がある場合があります。時計回りまたは反時計回りの回転を強制することもできます。私はそれが役立つことを願っています。
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);
}
}
}
使用法:
ProgressBarAnimation progressBarAnimation = new ProgressBarAnimation(progressBar, 1000);
// Example 1
progressBarAnimation.setProgressAndRotation(newProgress, newRotation);
// Example 2
progressBarAnimation.setProgressOnly(newProgress);
// Example 3
progressBarAnimation.setRotationOnly(newRotation);