5

I am trying to implement a simple circular progress bar. It works fine, but I can't seem to be able to make the corners of the progress circle rounded.

I'm trying to achieve something like this: enter image description here

My code :

<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape
            android:thickness="3dp"
            android:shape="ring"
            android:type="sweep"
            android:useLevel="false">

            <solid android:color="@color/light_grey"/>
        </shape>
    </item>

    <item android:id="@android:id/progress">
        <rotate
            android:fromDegrees="270"
            android:toDegrees="270">

            <shape
                android:thickness="3dp"
                android:shape="ring"
                android:type="sweep"
                android:useLevel="true">

                <solid android:color="@color/green"/>
                <corners android:radius="8dp"/> // --> this has no effect whatsoever
            </shape>
        </rotate>
    </item>
</layer-list>
BVtp
  • 2,308
  • 2
  • 29
  • 68
  • Can u share what is your expected output – AskNilesh Jan 30 '19 at 11:24
  • @NileshRathod I updated my post with an example of what I'm trying to achieve. thank you – BVtp Jan 30 '19 at 11:29
  • https://stackoverflow.com/questions/36639660/android-circular-progress-bar-with-rounded-corners – AskNilesh Jan 30 '19 at 11:37
  • https://stackoverflow.com/questions/14688117/how-to-make-circle-custom-progress-bar-in-android – Athira Jan 30 '19 at 11:38
  • 1
    All this didn't help unfortunately. The solutions there either refer to external 3-party libraries or provide code in Kotlin, or simply do not work. – BVtp Jan 30 '19 at 11:42

1 Answers1

1

A little late but you can create a custom circular progress view like this

class CircularProgressView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private lateinit var progressPaint: Paint
    private lateinit var backgroundPaint: Paint
    var max = MAX_PROGRESS
    var progress = START_PROGRESS
        set(value) {
            angle = calculateAngle(value)
            invalidate()
        }

    private val rect = RectF()
    private var diameter = 0F
    private var angle = 0F

    init {
        attrs?.let {
            val typedArray = context.obtainStyledAttributes(it, R.styleable.CircularProgressView, 0, 0)
            val stroke = typedArray.getDimension(R.styleable.CircularProgressView_stroke, context.resources.getDimension(R.dimen._1dp))
            val backgroundColor = typedArray.getColor(R.styleable.CircularProgressView_backgroundColor, ContextCompat.getColor(context, R.color.gray))
            val progressColor = typedArray.getColor(R.styleable.CircularProgressView_progressColor, ContextCompat.getColor(context, R.color.black))
            progressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                style = Paint.Style.STROKE
                strokeWidth = stroke
                color = progressColor
                strokeCap = Paint.Cap.ROUND
            }
            backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                style = Paint.Style.STROKE
                strokeWidth = stroke
                color = backgroundColor
            }
            max = typedArray.getFloat(R.styleable.CircularProgressView_max, MAX_PROGRESS)
            progress = typedArray.getFloat(R.styleable.CircularProgressView_progress, START_PROGRESS)
            typedArray.recycle()
        }
    }

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

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

    fun setProgressColor(@ColorRes color: Int) {
        progressPaint.color = ContextCompat.getColor(context, color)
        invalidate()
    }

    fun setProgressBackgroundColor(@ColorRes color: Int) {
        backgroundPaint.color = ContextCompat.getColor(context, color)
        invalidate()
    }

    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, START_ANGLE, angle, false, paint)
    }

    private fun calculateAngle(progress: Float) = MAX_ANGLE / max * progress

    companion object {
        private const val START_ANGLE = -90F
        private const val MAX_ANGLE = 360F
        private const val MAX_PROGRESS = 100F
        private const val START_PROGRESS = 0F
    }
}

The attrs

<declare-styleable name="CircularProgressView">
        <attr name="progress" format="float" />
        <attr name="max" format="float" />
        <attr name="stroke" format="dimension" />
        <attr name="backgroundColor" format="color" />
        <attr name="progressColor" format="color" />
</declare-styleable>
Juan Fraga
  • 434
  • 3
  • 9