Android circular progress bar with rounded corners

Rakesh picture Rakesh · Apr 15, 2016 · Viewed 10.6k times · Source

I am trying to get a circular progress bar with rounded corner as shown below. enter image description here

But I am not able to get the rounded corner so far I am able to get the circular progress bar. enter image description here

I am trying to draw it using the xml drawable.

 <ProgressBar
                android:id="@+id/onboarding_activity_progress_bar"
                android:layout_gravity="center"
                android:padding="10dp"
                android:layout_width="120dp"
                android:layout_height="120dp"
                style="?android:attr/progressBarStyleHorizontal"
                android:progressDrawable="@drawable/progressbar_onboarding_view"
                tools:progress="60"/>

Progressbar_onboarding_view.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape android:useLevel="false"
               android:innerRadiusRatio="2.0"
               android:shape="ring"
               android:thickness="10dp">
            <solid android:color="@color/progress_bar_background_color" />
            <corners android:radius="50dp"/>
        </shape>
    </item>
    <item android:id="@android:id/progress">
        <shape
              xmlns:android="http://schemas.android.com/apk/res/android"
              android:useLevel="true"
              android:innerRadiusRatio="2.0"
              android:shape="ring"
              android:thickness="10dp">
            <solid android:color="@color/progress_bar_color" />
        </shape>
        <!--
        <scale
              android:drawable="@drawable/progressbar_round_corner"
              android:scaleWidth="98%" /> -->
    </item>
</layer-list>

progressbar_rounded_corner.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

   <corners
         android:radius="10dp"/>

   <solid android:color="@android:color/white" />

   <stroke
         android:width="1dp"
         android:color="@android:color/holo_red_dark" />

</shape>

I tried using scale parameter but the progress corner didn't change. I am not sure how to achieve the rounded corner. Please help I would really appreciate it.

Answer

EyesClear picture EyesClear · Dec 18, 2018

A simple and efficient class extending View to draw circular progress, with rounded corners as an option. Progress color, background color, stroke width are also customizable.

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import androidx.annotation.FloatRange

class CircularProgressView : View {
  constructor(context: Context) : super(context)
  constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
  constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

  private val progressPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    style = Paint.Style.STROKE
  }
  private val backgroundPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    style = Paint.Style.STROKE
  }

  private val rect = RectF()
  private val startAngle = -90f
  private val maxAngle = 360f
  private val maxProgress = 100

  private var diameter = 0f
  private var angle = 0f

  override fun onDraw(canvas: Canvas) {
    drawCircle(maxAngle, canvas, backgroundPaint)
    drawCircle(angle, canvas, progressPaint)
  }

  override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
    diameter = Math.min(width, height).toFloat()
    updateRect()
  }

  private fun updateRect() {
    val strokeWidth = backgroundPaint.strokeWidth
    rect.set(strokeWidth, strokeWidth, diameter - strokeWidth, diameter - strokeWidth)
  }

  private fun drawCircle(angle: Float, canvas: Canvas, paint: Paint) {
    canvas.drawArc(rect, startAngle, angle, false, paint)
  }

  private fun calculateAngle(progress: Float) = maxAngle / maxProgress * progress

  fun setProgress(@FloatRange(from = 0.0, to = 100.0) progress: Float) {
    angle = calculateAngle(progress)
    invalidate()
  }

  fun setProgressColor(color: Int) {
    progressPaint.color = color
    invalidate()
  }

  fun setProgressBackgroundColor(color: Int) {
    backgroundPaint.color = color
    invalidate()
  }

  fun setProgressWidth(width: Float) {
    progressPaint.strokeWidth = width
    backgroundPaint.strokeWidth = width
    updateRect()
    invalidate()
  }

  fun setRounded(rounded: Boolean) {
    progressPaint.strokeCap = if (rounded) Paint.Cap.ROUND else Paint.Cap.BUTT
    invalidate()
  }
}