package io.virtualapp.widgets; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import java.util.ArrayList; import java.util.HashMap; public abstract class Indicator extends Drawable implements Animatable { private static final Rect ZERO_BOUNDS_RECT = new Rect(); protected Rect drawBounds = ZERO_BOUNDS_RECT; private HashMap<ValueAnimator, ValueAnimator.AnimatorUpdateListener> mUpdateListeners = new HashMap<>(); private ArrayList<ValueAnimator> mAnimators; private int alpha = 255; private boolean mHasAnimators; private Paint mPaint = new Paint(); public Indicator() { mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); } public int getColor() { return mPaint.getColor(); } public void setColor(int color) { mPaint.setColor(color); } @Override public int getAlpha() { return alpha; } @Override public void setAlpha(int alpha) { this.alpha = alpha; } @Override public int getOpacity() { return PixelFormat.OPAQUE; } @Override public void setColorFilter(ColorFilter colorFilter) { } @Override public void draw(Canvas canvas) { draw(canvas, mPaint); } public abstract void draw(Canvas canvas, Paint paint); public abstract ArrayList<ValueAnimator> onCreateAnimators(); @Override public void start() { ensureAnimators(); if (mAnimators == null) { return; } // If the animators has not ended, do nothing. if (isStarted()) { return; } startAnimators(); invalidateSelf(); } private void startAnimators() { for (int i = 0; i < mAnimators.size(); i++) { ValueAnimator animator = mAnimators.get(i); //when the animator restart , add the updateListener again because they // was removed by animator stop . ValueAnimator.AnimatorUpdateListener updateListener = mUpdateListeners.get(animator); if (updateListener != null) { animator.addUpdateListener(updateListener); } animator.start(); } } private void stopAnimators() { if (mAnimators != null) { for (ValueAnimator animator : mAnimators) { if (animator != null && animator.isStarted()) { animator.removeAllUpdateListeners(); animator.end(); } } } } private void ensureAnimators() { if (!mHasAnimators) { mAnimators = onCreateAnimators(); mHasAnimators = true; } } @Override public void stop() { stopAnimators(); } private boolean isStarted() { for (ValueAnimator animator : mAnimators) { return animator.isStarted(); } return false; } @Override public boolean isRunning() { for (ValueAnimator animator : mAnimators) { return animator.isRunning(); } return false; } /** * Your should use this to add AnimatorUpdateListener when * create animator , otherwise , animator doesn't work when * the animation restart . * * @param updateListener */ public void addUpdateListener(ValueAnimator animator, ValueAnimator.AnimatorUpdateListener updateListener) { mUpdateListeners.put(animator, updateListener); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); setDrawBounds(bounds); } public void setDrawBounds(int left, int top, int right, int bottom) { this.drawBounds = new Rect(left, top, right, bottom); } public void postInvalidate() { invalidateSelf(); } public Rect getDrawBounds() { return drawBounds; } public void setDrawBounds(Rect drawBounds) { setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom); } public int getWidth() { return drawBounds.width(); } public int getHeight() { return drawBounds.height(); } public int centerX() { return drawBounds.centerX(); } public int centerY() { return drawBounds.centerY(); } public float exactCenterX() { return drawBounds.exactCenterX(); } public float exactCenterY() { return drawBounds.exactCenterY(); } }