How to draw a circle with animation in android with circle size based on a value How to draw a circle with animation in android with circle size based on a value android android

How to draw a circle with animation in android with circle size based on a value


You have to draw the circle view, and after that you should create an animation to it.

Creating the circle view:

public class Circle extends View {    private static final int START_ANGLE_POINT = 90;    private final Paint paint;    private final RectF rect;    private float angle;    public Circle(Context context, AttributeSet attrs) {        super(context, attrs);        final int strokeWidth = 40;        paint = new Paint();        paint.setAntiAlias(true);        paint.setStyle(Paint.Style.STROKE);        paint.setStrokeWidth(strokeWidth);        //Circle color        paint.setColor(Color.RED);        //size 200x200 example        rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth);        //Initial Angle (optional, it can be zero)        angle = 120;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);    }    public float getAngle() {        return angle;    }    public void setAngle(float angle) {        this.angle = angle;    }}

Creating the animation class to set the new angle:

public class CircleAngleAnimation extends Animation {    private Circle circle;    private float oldAngle;    private float newAngle;    public CircleAngleAnimation(Circle circle, int newAngle) {        this.oldAngle = circle.getAngle();        this.newAngle = newAngle;        this.circle = circle;    }    @Override    protected void applyTransformation(float interpolatedTime, Transformation transformation) {        float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);        circle.setAngle(angle);        circle.requestLayout();    }}

Put circle into your layout:

<com.package.Circle    android:id="@+id/circle"    android:layout_width="300dp"    android:layout_height="300dp" />

And finally starting the animation:

Circle circle = (Circle) findViewById(R.id.circle);CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);animation.setDuration(1000);circle.startAnimation(animation);

The result is:enter image description here


As extra from @JohnCordeiro answer.I have added parameters from xml to reuse the circle and to fill the circle if needed.

class RecordingCircle(context: Context, attrs: AttributeSet) : View(context, attrs) {private val paint: Paintprivate val rect: RectFprivate val fillPaint: Paintprivate val fillRect: RectFvar angle: Floatvar startAngle: Floatinit {    val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecordingCircle)    startAngle = typedArray.getFloat(R.styleable.RecordingCircle_startAngle, 0f)    val offsetAngle = typedArray.getFloat(R.styleable.RecordingCircle_offsetAngle, 0f)    val color = typedArray.getColor(R.styleable.RecordingCircle_color, ResourcesCompat.getColor(resources, R.color.recording, null))    val strokeWidth = typedArray.getFloat(R.styleable.RecordingCircle_strokeWidth, 20f)    val circleSize = typedArray.getDimension(R.styleable.RecordingCircle_cicleSize, 100f)    val fillColor = typedArray.getColor(R.styleable.RecordingCircle_fillColor, 0)    typedArray.recycle()    paint = Paint().apply {        setAntiAlias(true)        setStyle(Paint.Style.STROKE)        setStrokeWidth(strokeWidth)        setColor(color)    }    rect = RectF(        strokeWidth,        strokeWidth,        (circleSize - strokeWidth),        (circleSize - strokeWidth)    )    fillPaint = Paint().apply {        setAntiAlias(true)        setStyle(Paint.Style.FILL)        setColor(fillColor)    }    val offsetFill = strokeWidth    fillRect = RectF(        offsetFill,        offsetFill,        (circleSize - offsetFill),        (circleSize - offsetFill)    )    //Initial Angle (optional, it can be zero)    angle = offsetAngle}override protected fun onDraw(canvas: Canvas) {    super.onDraw(canvas)    if (fillColor > 0) {        canvas.drawArc(rect, 0f, 360f, false, fillPaint)    }    canvas.drawArc(rect, startAngle, angle, false, paint)}}

And on the xml:

        <com.myapp.RecordingCircle android:id="@+id/cameraRecordButton"        android:layout_width="match_parent"        android:layout_height="match_parent"        app:offsetAngle="360"        app:color="@color/light_grey"        app:strokeWidth="10"        app:cicleSize="@dimen/camera_record_button"        app:fillColor="@color/recording_bg" />    <com.myapp.RecordingCircle android:id="@+id/progress"        android:layout_width="match_parent"        android:layout_height="match_parent"        app:startAngle="270"        app:color="@color/recording"        app:strokeWidth="10"        app:cicleSize="@dimen/camera_record_button" />

Here the result: Note the semi-transparent fill of the button

enter image description here


Added code for calculating correct circle measurements

import android.content.Contextimport android.graphics.Canvasimport android.graphics.Colorimport android.graphics.Paintimport android.graphics.RectFimport android.util.AttributeSetimport android.view.Viewimport androidx.core.content.ContextCompatclass Circle(context: Context, attrs: AttributeSet) : View(context, attrs) {    private val paint: Paint    private val rect: RectF    var angle = 0f    companion object {        private val START_ANGLE_POINT = 270f    }    init {        val strokeWidth = resources.getDimension(R.dimen.toast_circle_stroke_width)        paint = Paint().apply {            setAntiAlias(true)            setStyle(Paint.Style.STROKE)            setStrokeWidth(strokeWidth)            setColor(Color.RED)        }        val circleSize = resources.getDimension(R.dimen.toast_circle_size)        rect = RectF(            strokeWidth,            strokeWidth,            circleSize + strokeWidth,            circleSize + strokeWidth        )    }    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {        val circleSize = resources.getDimension(R.dimen.toast_circle_size).toInt()        val strokeWidth = resources.getDimension(R.dimen.toast_circle_stroke_width).toInt()        super.onMeasure(            MeasureSpec.makeMeasureSpec(circleSize + 2 * strokeWidth, MeasureSpec.EXACTLY),            MeasureSpec.makeMeasureSpec(circleSize + 2 * strokeWidth, MeasureSpec.EXACTLY));    }    override fun onDraw(canvas: Canvas) {        super.onDraw(canvas)        canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint)    }}