Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I want to develop a custom component which draws part of the circle based on different values. e.g draw 1/4 cirle, 1/2 circle etc. The component needs to be animated to display drawing process. The partial circle is drawn on top of a static imageview, and I plan to use two views, animated one on top of the static one. Any suggestion how to develop this?

I put the screenshot for reference.

enter image description here

Please refer to the picture, and get a feel how it looks like. Thanks!

Thanks in advance.

like image 460
Leon Li Avatar asked Apr 01 '15 01:04

Leon Li


2 Answers

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

like image 70
John Cordeiro Avatar answered Sep 24 '22 11:09

John Cordeiro


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: Paint private val rect: RectF  private val fillPaint: Paint private val fillRect: RectF  var angle: Float var startAngle: Float  init {     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

like image 21
Sulfkain Avatar answered Sep 21 '22 11:09

Sulfkain