2011-11-07 155 views
26

我在我的應用程序中使用ProgressBar,我在onync_update更新了ASyncTask。 目前爲止這麼好。我想要做的是動畫進度更新,以便它不僅「跳」到值,而是順利移動到該值。在Android中動畫進度條更新

我試着這樣做運行下面的代碼:

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()也沒有幫助。 任何想法?謝謝!

回答

110

我用的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); 

注:如果從和值過低,產生平滑的動畫只是將它們相乘由100左右。如果你這樣做,不要忘記也要乘以setMax(..)。

+6

像巧克力一樣工作。謝謝.. –

+1

工作就像一個魅力! - 感謝分享這個代碼。 –

+1

@EliKonky。工作很好。工作正常。我有個問題。我想在達到100(最大值)後隱藏進度條。在達到最大值後如何設置其可見性?請幫助我。 –

1

你可以嘗試使用一個處理程序/可運行的,而不是...

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); 
2

編輯:雖然我的答案的作品,禮Konkys回答是好。用它。

如果您的線程在UI線程上運行,那麼它必須交出UI線程才能讓視圖有機會更新。目前你告訴進度條「更新到1,更新到2,更新到3」,而不用釋放UI線程,因此它實際上可以更新。

解決這個問題的方法是使用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線程 沒有結果。不得不操縱線程和/或處理程序。「

+0

真棒,感謝的作品! – user1033552

7

這裏是@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); 
+0

太棒了!謝謝 – bmelnychuk

26

我使用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(); 
+6

應該是in ;-)並且可能是0到100(但是你應該在progreso上設置Max(100)來確認,但是其他的好,比其他的答案更好, –

+1

好多了,然後AsyncTask – dasar

0

這裏是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);