Skip to content

Instantly share code, notes, and snippets.

@avatsav
Created March 9, 2015 12:30
Show Gist options
  • Save avatsav/1bedd061dc7be76ceb07 to your computer and use it in GitHub Desktop.
Save avatsav/1bedd061dc7be76ceb07 to your computer and use it in GitHub Desktop.
BellyProgressbar
public class BellyProgressBar extends ProgressBar {
private int mColor;
private float mStrokeWidth;
private float mRotationSpeed = 1f;
public BellyProgressBar(Context context) {
super(context);
init(context);
}
public BellyProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public BellyProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mColor = context.getResources().getColor(R.color.payment_progress_bar_default_color);
mStrokeWidth = context.getResources().getDimension(R.dimen.bpb_default_stroke_width);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
setIndeterminateDrawable(new BellyProgressDrawable(mColor, mStrokeWidth, mRotationSpeed));
}
public void setBellyColor(int color) {
mColor = color;
checkIndeterminateDrawable().setBellyColor(mColor);
}
public void setStrokeWidth(float strokeWidth) {
mStrokeWidth = strokeWidth;
checkIndeterminateDrawable().setStrokeWidth(mStrokeWidth);
}
public void setRotationSpeed(float speed) {
mRotationSpeed = speed;
checkIndeterminateDrawable().setRotationSpeed(mRotationSpeed);
}
public void progressiveStop() {
checkIndeterminateDrawable().stop();
}
private BellyProgressDrawable checkIndeterminateDrawable() {
Drawable ret = getIndeterminateDrawable();
if (ret == null || !(ret instanceof BellyProgressDrawable))
throw new RuntimeException("The drawable is not a BellyProgressDrawable");
return (BellyProgressDrawable) ret;
}
}
public class BellyProgressDrawable extends Drawable implements Animatable {
private static final Interpolator ROTATION_INTERPOLATOR = null; //new CubicBezierInterpolator(0.4, 0, 0.2, 1); //Ease-in-out
private static final int ROTATION_ANIMATOR_DURATION = 1500; //ms
private Rect fBounds = new Rect();
private Paint mPaint;
private ValueAnimator mRotationAnimator;
private float mCurrentRotationAngle;
private float mOuterRadius;
private float mInnerRadius;
private float[] mOuterCircleCenter;
private float[] mInnerCircleCenter;
private boolean mRunning;
//params
private int mColor;
private float mStrokeWidth;
private float mRotationSpeed;
public BellyProgressDrawable(int color, float strokeWidth, float rotationSpeed) {
mColor = color;
mStrokeWidth = strokeWidth;
mRotationSpeed = rotationSpeed;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mColor);
setupAnimations();
}
@Override
public void draw(Canvas canvas) {
canvas.save();
canvas.rotate(mCurrentRotationAngle, fBounds.centerX(), fBounds.centerY());
mPaint.setXfermode(null);
canvas.drawCircle(mOuterCircleCenter[0], mOuterCircleCenter[1], mOuterRadius, mPaint); //DST
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
canvas.drawCircle(mInnerCircleCenter[0], mInnerCircleCenter[1], mInnerRadius, mPaint); //SRC
canvas.restore();
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
// Called only once! Much performance! Such smooth! So awesome!
calculateCircleMeasurements();
}
private void calculateCircleMeasurements() {
fBounds = getBounds();
float size = Math.min(fBounds.height(), fBounds.width());
mOuterRadius = (size / 2) - mStrokeWidth / 2;
mInnerRadius = (size / 2) - (3 * mStrokeWidth) / 2;
// Outer circle center;
mOuterCircleCenter = new float[2];
mOuterCircleCenter[0] = fBounds.centerX();
mOuterCircleCenter[1] = fBounds.centerY() - mStrokeWidth / 2;
// Inner mask circle center;
mInnerCircleCenter = new float[2];
mInnerCircleCenter[0] = fBounds.centerX();
mInnerCircleCenter[1] = fBounds.centerY();
}
private void setupAnimations() {
mRotationAnimator = ValueAnimator.ofFloat(0f, 360f);
//mRotationAnimator.setInterpolator(ROTATION_INTERPOLATOR);
mRotationAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float angle = getAnimatedFraction(animation) * 360f;
setCurrentRotationAngle(angle);
}
});
mRotationAnimator.setDuration((long) (ROTATION_ANIMATOR_DURATION / mRotationSpeed));
mRotationAnimator.setRepeatCount(ValueAnimator.INFINITE);
mRotationAnimator.setRepeatMode(ValueAnimator.RESTART);
}
private float getAnimatedFraction(ValueAnimator animation) {
float fraction = animation.getDuration() > 0 ? ((float) animation.getCurrentPlayTime()) / animation.getDuration() : 1f;
fraction %= 1f;
fraction = min(fraction, 1f);
fraction = animation.getInterpolator().getInterpolation(fraction);
return fraction;
}
private void setCurrentRotationAngle(float currentRotationAngle) {
mCurrentRotationAngle = currentRotationAngle;
invalidateSelf();
}
@Override
public void start() {
if (isRunning())
return;
mRunning = true;
mRotationAnimator.start();
invalidateSelf();
}
@Override
public void stop() {
if (!isRunning())
return;
mRunning = false;
mRotationAnimator.cancel();
invalidateSelf();
}
public void setBellyColor(int newColor) {
mColor = newColor;
mPaint.setColor(mColor);
}
public void setStrokeWidth(float strokeWidth) {
mStrokeWidth = strokeWidth;
calculateCircleMeasurements();
}
public void setRotationSpeed(float speed) {
mRotationSpeed = speed;
mRotationAnimator.setDuration((long) (ROTATION_ANIMATOR_DURATION / mRotationSpeed));
setupAnimations();
invalidateSelf();
}
@Override
public boolean isRunning() {
return mRunning;
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSPARENT;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment