ProgressBarの値をアニメーションで変更する

f:id:tomorrowkey:20160229190212g:plain ↑こういうことやりたいんだけど、ProgressBar#setProgress(:int)だとアニメーションしてくれない。

そうだ、ObjectAnimatorを使ってアニメーションを実現しよう。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  tools:context=".activity.MainActivity"
  >
  <LinearLayout
    android:orientation="vertical"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ProgressBar
      style="?android:attr/progressBarStyleHorizontal"
      android:id="@+id/progress_bar"
      android:layout_margin="16dp"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>

    <Button
      android:id="@+id/update_progress_button"
      android:text="Update progress"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/>
  </LinearLayout>
</layout>
public class MainActivity extends AppCompatActivity {

  ActivityMainBinding binding;

  ObjectAnimator objectAnimator;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    binding.updateProgressButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        int progress = (int) (Math.random() * 100);
        setProgressWithAnimation(progress);
      }
    });
  }

  private void setProgressWithAnimation(int progress) {
    int[] values = {binding.progressBar.getProgress(), progress};
    if (objectAnimator == null) {
      objectAnimator = ObjectAnimator.ofInt(binding.progressBar, "progress", values);
    } else {
      objectAnimator.cancel();
      objectAnimator.setIntValues(values);
    }
    objectAnimator.setDuration(1000);
    objectAnimator.setInterpolator(new DecelerateInterpolator(2.0f));
    objectAnimator.start();
  }

}

Activityに書いちゃうとアレなんでカスタムViewでやるとスッキリしそうでよさそう。 アニメーションしている最中はそのときのProgressの値になってしまうので、getProgress()を使いたいケースではこれは使えない。