I finally made a custom View to achieve that:
public class ArcProgressView extends View {
private int width;
private float startAngle;
private float endAngle;
private float progressAngle;
private RectF bounds;
private Paint circlePaint;
private Paint textPaint;
private float progress;
public ArcProgressView(Context context, AttributeSet attributeSet) {
super(context,attributeSet);
init();
}
public void init(){
circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeWidth(15);
circlePaint.setStrokeCap(Paint.Cap.ROUND);
circlePaint.setColor(Color.rgb(254,54,115));
textPaint = new Paint();
textPaint.setColor(Color.rgb(254,54,115));
textPaint.setTextSize(50);
calcBounds();
}
private void calcBounds(){
int offsetY = 300; // The amount of Y offset
int offset = 400; // the amount of circle offscreen
// Tweak as you prefer
bounds = new RectF(0,offsetY,width+offset,width+offset+offsetY);
bounds.offset(-offset /2 ,0);
float r = bounds.width()/2; //the radius of the circle
float x = width/2;
float startY = (float) (bounds.centerY() - Math.sqrt(r * r - x * x));
startAngle = (float) (180 / Math.PI * Math.atan2(startY - bounds.centerY() , 0 - bounds.centerX()));
endAngle = (float) (180 / Math.PI * Math.atan2(startY - bounds.centerY() , width - bounds.centerX()));
}
@Override
protected void onDraw(Canvas canvas) {
if(width != getWidth()) {
width = getWidth();
calcBounds();
}
canvas.drawArc(bounds,startAngle, progressAngle,false,circlePaint);
String progressText = (int)progress + "%";
canvas.drawText(progressText,bounds.centerX() - textPaint.measureText(progressText) / 2,bounds.centerY(),textPaint);
super.onDraw(canvas);
}
public void setProgress(float progress){
this.progress = progress;
progressAngle = (endAngle-startAngle)*(progress/100f);
invalidate();
}
}
the result looks like this

How is it done?
- We create a RectF bigger than screen width by some offset (this will contain our circle)
- We calculate the Y intersection of the circle with the screen bounds with
(float) (bounds.centerY() - Math.sqrt(r * r - x * x));
- We calculate the angle between the start and ending point using
Math.atan2()
startAngle = (float) (180 / Math.PI * Math.atan2(startY - bounds.centerY() , 0 - bounds.centerX()));
endAngle = (float) (180 / Math.PI * Math.atan2(startY - bounds.centerY() , width - bounds.centerX()));
- Interpolate between the two angles with this
(endAngle-startAngle)*(progress/100f);
- Draw the arc and the text
Hope this helps!