Android circular progress bar with rounded corners

14,825

Solution 1

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()
  }
}

Solution 2

Use the Material CircularProgressIndicator and use app:trackCornerRadius="5dp" to get the curved progress indicator.

  <com.google.android.material.progressindicator.CircularProgressIndicator
            app:indicatorSize="95dp"
            android:progress="60"
            app:trackCornerRadius="5dp"
            app:trackThickness="6dp"
            app:trackColor="@color/track_color"
            app:indicatorColor="@color/yellow_percent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

Solution 3

I know this is an old question. But here is a solution which might be helpful to someone else.

This library can be used to achieve this.

Simply add this to your Gradel File

compile 'pl.pawelkleczkowski.customgauge:CustomGauge:1.0.3'

And then add this to you XML Layout

   <pl.pawelkleczkowski.customgauge.CustomGauge
        android:id="@+id/gauge2"
        android:layout_width="140dp"
        android:layout_height="140dp"
        android:layout_centerHorizontal="true"
        android:paddingBottom="10dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="10dp"
        app:gaugeEndValue="100"
        app:gaugePointEndColor="@color/md_blue_800"
        app:gaugePointStartColor="@color/md_blue_300"
        app:gaugeStartAngle="180"
        app:gaugeStartValue="0"
        app:gaugeStrokeCap="ROUND"
        app:gaugeStrokeColor="@color/md_grey_400"
        app:gaugeStrokeWidth="10dp"
        app:gaugeSweepAngle="360" />

And this is how you can set the progress of the bar

private CustomGauge gauge;// Declare this variable in your activity

gauge = findViewById(R.id.gauge2);//And this on you OnCreate method

gauge.setValue(progress);// Set the progress like this.

The library is Opensource and is available to use under the General Public License, version 2

Solution 4

Library

compile 'pl.pawelkleczkowski.customgauge:CustomGauge:1.0.4'

XML CODE

<pl.pawelkleczkowski.customgauge.CustomGauge
            android:id="@+id/progressbar"
            android:layout_width="@dimen/dimens_550px"
            android:layout_height="@dimen/dimens_550px"

            app:layout_constraintStart_toStartOf="@id/lottie_empty"
            app:layout_constraintEnd_toEndOf="@id/lottie_empty"
            app:layout_constraintTop_toTopOf="@id/lottie_empty"
            app:layout_constraintBottom_toBottomOf="@id/lottie_empty"
            android:paddingBottom="10dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="10dp"


            app:gaugePointEndColor="#3DEBFF"
            app:gaugePointStartColor="#246887"
            app:gaugeStartAngle="270"
            app:gaugeStrokeCap="ROUND"
            app:gaugeStrokeColor="#80777777"
            app:gaugeStrokeWidth="10dp"
            app:gaugeSweepAngle="360"
            
            />

Code java

private CustomGauge gauge;// Declare this variable in your activity
gauge = findViewById(R.id.gauge2);//And this on you OnCreate method
gauge.setEndValue(max_progress);// Set the max progress like this.
gauge.setValue(progress);// Set the progress like this.

Image from my apk

Share:
14,825

Related videos on Youtube

Rakesh
Author by

Rakesh

Hi, I'm Rakesh, a Staff Software Engineer with extensive experience in highly distributed &amp; scalable systems Website: http://portfolio.rakeshkumar.info

Updated on April 29, 2021

Comments

  • Rakesh
    Rakesh about 3 years

    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.

    • Pavya
      Pavya about 8 years
      add corner to in @android:id/progress
    • Rakesh
      Rakesh about 8 years
      @Pravin I tried it already but it didn't work. It seems corner is only for rectangle shape.
    • Vipul Asri
      Vipul Asri about 8 years
      Try this library for the same :Progress Widget
    • Rakesh
      Rakesh about 8 years
      @VipulAsri thank you for the suggestion but I don't want to use a third party library. Because I want to be under dex limit and my app is already very close to dex limit.
    • satorikomeiji
      satorikomeiji about 8 years
    • kukku
      kukku over 6 years
      u should go for custom progress bar
    • M. Reza Nasirloo
      M. Reza Nasirloo about 6 years
      Did you find any solution?
    • Rahulrr2602
      Rahulrr2602 about 6 years
      @M.RezaNasirloo I have posted an answer which might be helpful to you.
    • iamnaran
      iamnaran over 5 years
      @VipulAsri did you find any solution?
    • Nate T
      Nate T about 3 years
      If it were me, I'd use a GIF. Once in a while, the simplest solution and the best solution are one and the same... BTW if you use this solution, let me know so I can add an answer and get the rep. ( :
  • Marat
    Marat about 4 years
    Thank you for great solution! One clarification question: In updateRect method, to get the circles drawn edge to edge, isn't it better to divide obtained strokeWidth by 2 before setting rect coordinates? With current setup there are small paddings around the rectangle.
  • David Rector
    David Rector over 2 years
    What language is this written in?
  • Prateek
    Prateek over 2 years
    above program written in Kotlin