Here is a simple solution.
CircleProgressBar.java
public class CircleProgressBar extends View { /** * ProgressBar's line thickness */ private float strokeWidth = 4; private float progress = 0; private int min = 0; private int max = 100; /** * Start the progress at 12 o'clock */ private int startAngle = -90; private int color = Color.DKGRAY; private RectF rectF; private Paint backgroundPaint; private Paint foregroundPaint; /**Animation duration */ private int animDuration = 5000; public float getStrokeWidth() { return strokeWidth; } public void setStrokeWidth(float strokeWidth) { this.strokeWidth = strokeWidth; backgroundPaint.setStrokeWidth(strokeWidth); foregroundPaint.setStrokeWidth(strokeWidth); invalidate(); requestLayout();//Because it should recalculate its bounds } public float getProgress() { return progress; } public void setProgress(float progress) { this.progress = progress; invalidate(); } public int getMin() { return min; } public void setMin(int min) { this.min = min; invalidate(); } public int getMax() { return max; } public void setMax(int max) { this.max = max; invalidate(); } public int getColor() { return color; } public void setColor(int color) { this.color = color; backgroundPaint.setColor(adjustAlpha(color, 0.3f)); foregroundPaint.setColor(color); invalidate(); requestLayout(); } public int getAnimDuration() { return animDuration; } public void setAnimDuration(int animDuration) { this.animDuration = animDuration; } public CircleProgressBar(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context, AttributeSet attrs) { rectF = new RectF(); TypedArray typedArray = context.getTheme().obtainStyledAttributes( attrs, R.styleable.CircleProgressBar, 0, 0); //Reading values from the XML layout try { strokeWidth = typedArray.getDimension(R.styleable.CircleProgressBar_progressBarThickness, strokeWidth); progress = typedArray.getFloat(R.styleable.CircleProgressBar_my_circle_progress, progress); color = typedArray.getInt(R.styleable.CircleProgressBar_progressbarColor, color); min = typedArray.getInt(R.styleable.CircleProgressBar_min, min); max = typedArray.getInt(R.styleable.CircleProgressBar_max, max); } finally { typedArray.recycle(); } backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); backgroundPaint.setColor(adjustAlpha(color, 0.3f)); backgroundPaint.setStyle(Paint.Style.STROKE); backgroundPaint.setStrokeWidth(strokeWidth); foregroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); foregroundPaint.setColor(color); foregroundPaint.setStyle(Paint.Style.STROKE); foregroundPaint.setStrokeWidth(strokeWidth); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawOval(rectF, backgroundPaint); float angle = 360 * progress / max; canvas.drawArc(rectF, startAngle, angle, false, foregroundPaint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); final int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int min = Math.min(width, height); setMeasuredDimension(min, min); rectF.set(0 + strokeWidth / 2, 0 + strokeWidth / 2, min - strokeWidth / 2, min - strokeWidth / 2); } /** * Lighten the given color by the factor * * @param color The color to lighten * @param factor 0 to 4 * @return A brighter color */ public int lightenColor(int color, float factor) { float r = Color.red(color) * factor; float g = Color.green(color) * factor; float b = Color.blue(color) * factor; int ir = Math.min(255, (int) r); int ig = Math.min(255, (int) g); int ib = Math.min(255, (int) b); int ia = Color.alpha(color); return (Color.argb(ia, ir, ig, ib)); } /** * Transparent the given color by the factor * The more the factor closer to zero the more the color gets transparent * * @param color The color to transparent * @param factor 1.0f to 0.0f * @return int - A transplanted color */ public int adjustAlpha(int color, float factor) { int alpha = Math.round(Color.alpha(color) * factor); int red = Color.red(color); int green = Color.green(color); int blue = Color.blue(color); return Color.argb(alpha, red, green, blue); } /** * Set the progress with an animation. * Note that the {@link android.animation.ObjectAnimator} Class automatically set the progress * so don't call the {@link CircleProgressBar#setProgress(float)} directly within this method. * * @param progress The progress it should animate to it. */ public void setProgressWithAnimation(float progress) { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "progress", progress); objectAnimator.setDuration(animDuration); objectAnimator.setInterpolator(new DecelerateInterpolator(0.8f)); objectAnimator.start(); }
res / values / attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircleProgressBar"> <attr name="min" format="integer" /> <attr name="max" format="integer" /> <attr name="my_circle_progress" format="integer" /> <attr name="progressbarColor" format="color" /> <attr name="progressBarThickness" format="dimension" /> </declare-styleable> </resources>
Taken from here