final CustomDrawable customDrawable = new CustomDrawable();
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.setIndeterminate(true);
progressBar.setIndeterminateDrawable(customDrawable);
ProgressBar に RotateDrawable をセットすると回転するのは、このonLevelChange() を利用して角度を変えているからです。
public class CustomDrawable extends Drawable {
@Override
public void draw(Canvas canvas) {
// 繰り返し呼ばれる
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
protected boolean onLevelChange(int level) {
// 繰り返し呼ばれる
// level は 0 〜 10000
return super.onLevelChange(level);
}
}
この振る舞いは、Animatable を実装すると変わります。
onLevelChange() は呼ばれなくなり、そのままだと stop(), start() の後に draw() が1回だけ呼ばれます。
public class CustomDrawable extends Drawable implements Animatable {
@Override
public void draw(Canvas canvas) {
}
...
@Override
public void start() {
}
@Override
public void stop() {
}
@Override
public boolean isRunning() {
return false;
}
}
このままでは draw() が連続して呼ばれないのでアニメーションになりません。そのため、まず start() で内部のアニメーションを開始します。アニメーションを開始したら invalidateSelf() や scheduleSelf() を呼びます。また、draw() 内でもアニメーション中なら invalidateSelf() や scheduleSelf() を呼ぶようにします。これにより、アニメーション中は draw() が連続して呼ばれるようになります。
public class CustomDrawable extends Drawable implements Animatable {
...
private static final Interpolator cubicBezierInterpolator = PathInterpolatorCompat.create(0.66f, 0.22f, 0.21f, 1f);
private final int width;
private final int height;
private final RectF rectF;
private final ValueAnimator valueAnimator;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path path = new Path();
@Override
public int getIntrinsicWidth() {
return width;
}
@Override
public int getIntrinsicHeight() {
return height;
}
public CustomDrawable(Context context) {
float density = context.getResources().getDisplayMetrics().density;
width = (int) (density * 100);
height = (int) (density * 100);
rectF = new RectF(density * 6, density * 6, density * 94, density * 94);
valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setInterpolator(cubicBezierInterpolator);
paint.setColor(Color.parseColor("#0D47A1"));
paint.setStyle(Paint.Style.FILL);
}
@Override
public void draw(Canvas canvas) {
float factor = (float) valueAnimator.getAnimatedValue();
paint.setAlpha((int) (255 * (1f - factor)));
path.reset();
path.moveTo(width * 0.5f, height * 0.5f);
path.arcTo(rectF, -90, 360 * factor);
path.moveTo(width * 0.5f, height * 0.5f);
path.close();
canvas.drawPath(path, paint);
if (isStarted()) {
invalidateSelf();
}
}
@Override
public void start() {
if (isStarted()) {
return;
}
final Animator animator = valueAnimator;
animator.start();
invalidateSelf();
}
@Override
public void stop() {
final Animator animator = valueAnimator;
animator.end();
}
@Override
public boolean isRunning() {
final Animator animator = valueAnimator;
if (animator.isRunning()) {
return true;
}
return false;
}
private boolean isStarted() {
final Animator animator = valueAnimator;
if (animator.isStarted()) {
return true;
}
return false;
}
}
Animatable を実装しているクラスとして、AnimatedVectorDrawable や AnimationDrawable があります。
0 件のコメント:
コメントを投稿