Draw Circle in Canvas Android

Canvass animations: Simple Circle Progress View on Android

Photo by Daniel Cheung on Unsplash

Photo by Daniel Cheung on Unsplash

The Android Class class lets us describe anything* that we can imagine using basic shapes, paths, and bitmaps. The Canvass API information technology's really large 🤯 and daunting at first sight. Hither nosotros're merely going to scratch the surface to create our simple animation.

The animation

Total circle progress animation

Note

This article volition be roofing each step for conceiving the animation but I do recommend reading a fleck further: Getting started with drawing on the Android Sail by Rebecca Franks it's a not bad read 🤓.

Ok, lets started!

Y'all may know the drill. Create a new project, with an empty activity, and create a class that extends from the AndroidView grade:

          class CircularProgressView(
context: Context?,
attrs: AttributeSet?
) : View(context, attrs) {}

And now we accept our ready to describe on view! 🙌

What exercise we need to draw?

In gild to reach this animation nosotros start accept to know how to draw the circles, we need one to be the background and some other arc to fill the current progress.

Background arc at the left and inner arc to marking the progress at the correct.

And how tin we draw it?

Each view comes with a onDraw method override which provides us with a Canvas instance for us to beginning cartoon with. To achieve our blitheness we need to create depict two arcs using the canvas instance, ane arc for the background, and one of the tops, which will exist the one to be blithe. For that, we'll need to use the Canvas#drawArcmethod, which can let us draw a circle with nothing on the within.

Let'due south accept a look into information technology 🖌.

          public void drawArc (
RectF oval,
bladder startAngle,
float sweepAngle,
boolean useCenter,
Paint paint
)

Nice, but what do they mean?

  • The RectF oval is simply a holder for the coordinates needed to create an "invisible rectangle" in which our oval will exist contained. This oval is used to ascertain the shape and size of the arc.
  • startAngle: is the degree starting point from our oval from where we are going to beginning drawing the arc.
  • sweepAngle: means how much of the arc is going to be painted from the startAngle to this angle.
  • useCenter: the documentation explains information technology equally, if true, include the eye of the oval in the arc, and close information technology if information technology is being stroked. This will draw a wedge.
  • paint: this is the object that provides the information to the cartoon of how it should be stroked, it's color, and more.

Drawing the background circle 🎨

At present that we understand what we need in order to draw an arc, let's get to the code.

In our view's onDraw method nosotros should create our oval's RectF space with the correct dimensions nosotros desire our circle progress to have:

          // ...          private val ovalSpace = RectF()                    override fun onDraw(canvas: Canvas?) {
setSpace()
}individual fun setSpace() {
val horizontalCenter = (width.div(ii)).toFloat()
val verticalCenter = (height.div(2)).toFloat()
val ovalSize = 200
ovalSpace.set(
horizontalCenter - ovalSize,
verticalCenter - ovalSize,
horizontalCenter + ovalSize,
verticalCenter + ovalSize
)
}

As this won't be painted it would simply correspond an invisible oval infinite similar the following:

Invisible oval space representation.

After nosotros have our oval infinite nosotros tin use the canvas object to describe our arc on it. But in order to visualize it, we need a pigment object to pass the to the drawArc canvas method. Let's create it:

          // ...          private val parentArcColor = context?.resources?.getColor(R.color.gray_light, null) ?: Color.Greyness

private val parentArcPaint = Paint().apply {
manner = Pigment.Mode.STROKE
isAntiAlias = true
color = parentArcColor
strokeWidth = 40f
}

// ...

The paint object arguments are self-explanatory, merely a good thing to notation is to:

Use the isAntiAlias flag to ensure your drawing has smooth edges.

And let it be a circle 🎨

          // ...          override fun onDraw(canvas: Canvass?) {
setSpace()
canvas?.allow {
information technology.drawArc(ovalSpace, 0f, 360f, false, parentArcPaint)
}
}

In order to see anything, we need to make sure our custom view is added to the main activity layout. The name of the custom widget will be the name of our course in this case CirculaProgressView.

                      <com.labs.circularprogress.CircularProgressView
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

And nosotros will be able to run across:

Groundwork arc.

Drawing the inner circumvolve 🎨

Now that nosotros already know how to draw an arc, this part would be piece of cake, only declare a paint object for information technology and draw it on our onDraw method. At that place would be a few differences, but I'll be explaining each of the ones. Allow's encounter:

          // ...
private val fillArcPaint = Paint().apply {
way = Paint.Fashion.STROKE
isAntiAlias = true
color = fillArcColor
strokeWidth = 40f
// 1
strokeCap = Paint.Cap.ROUND
}
override fun onDraw(canvas: Canvass?) {
setSpace()
canvas?.permit {
// 2
drawBackgroundArc( it )
// 3
drawInnerArc( it )
}
}
individual fun drawBackgroundArc(it: Canvas) {
it.drawArc(ovalSpace, 0f, 360f, false, parentArcPaint)
}
individual fun drawInnerArc(canvas: Sheet) {
// 4
val percentageToFill = 180f
// 5
canvas.drawArc(ovalSpace, 270f, percentageToFill, faux, fillArcPaint)
}

Taking a look at the differences 🧐

  1. strokeCap = Pigment.Cap.Round this would brand the edge of the stroke while drawing to expect round instead of flat.

The left arc shows a square cap and the right a rounded ane.

2. We moved the logic to draw the background arc into it'due south own functions to improve readability at the onDraw method.

three. Created another office that will have care of drawing the inner arc.

4. We set the canvas#drawArc sweepAngle parameter to 180f every bit right now we merely want to draw half of the circle.

five. Here nosotros can notice a 270f value for our startAngle parameter, this is because the angle diagram does non outset equally nosotros use to. The 270f value will set the startAngle at the top as you could run across in the side by side image.

Android canvas angle system

Let's start with animations 🚀

Let'southward do a tiny recap. In order to exist able to draw something, we need to specify everything that nosotros want to show at our view onDraw office. Easy peasy right? At present… if we desire to display something new in our canvass nosotros need to describe everything we had before and then draw the new thing we want information technology to appear, in our instance this new thing would be an incrementing arc to prove the progress.

To achieve this we demand a few things:

  • A value that indicates the percent of our arc to draw and that we tin can change dynamically that can exist read from our onDraw function
  • Draw the new value
  • And call a redraw for our view
  • And repeat

First, let'southward alter our drawInnerArc function to use a dynamic currentPercentage value to determine the per centum fill to be drawn:

          private var currentPercentage = 0          //...          individual fun drawInnerArc(canvas: Canvas) {
val percentageToFill = getCurrentPercentageToFill()
canvas.drawArc(ovalSpace, 270f, percentageToFill, false, fillArcPaint)
}
private fun getCurrentPercentageToFill() =
(ARC_FULL_ROTATION_DEGREE * (currentPercentage / PERCENTAGE_DIVIDER)).toFloat()

To draw the new value, we have to ask the view for a redraw and this is done b calling the view invalidate() method when a redraw is needed.

At present nosotros'll create a function to be chosen when nosotros want to perform the animation. Hither we utilise Android'south ValueAnimatorclass to helps us change the the currentPercentage value through time and phone call our viewinvalidate() on each change, then it can be visualized.

The documentation defines the ValueAnimator class a a simple timing engine for running animations which summate animated values and set up them on target objects.

In our instance, we desire to breathing from values 0% to 100%, and this class will make achieve this animation a piece of cake. So let'south take a wait into the code, a, I'll explain each step on the go:

          fun animateProgress() {
// one
val valuesHolder = PropertyValuesHolder.ofFloat(
PERCENTAGE_VALUE_HOLDER,
0f,
100f
)

// ii
val animator = ValueAnimator().apply {
setValues(valuesHolder)
elapsing
= 1000
interpolator = AccelerateDecelerateInterpolator()

// three
addUpdateListener {
// iv
val pct = it.getAnimatedValue(PERCENTAGE_VALUE_HOLDER) as Float

// 5
currentPercentage = percentage.toInt()

// vi

invalidate()
}
}

// 7
animator.kickoff()
}
companion object {
// ...

const val PERCENTAGE_VALUE_HOLDER = "pct"
}
  1. We create a PropertyValuesHolder case for holding the values that we want to animate. In this case, we will animate from 0 to 100 percent. In social club to create this instance we also need to laissez passer a propertyName that we volition use afterward to grab the current animated value from the animator.
  2. Here we create an instance of ValueAnimator, nosotros set the holding values declared earlier and also pass how much time in milliseconds we want the animation to last.
  3. This will be called on every frame of the blitheness, providing us with the calculated percent value for a specific frame. This value will be used to update the currentPercentage animation later on.
  4. Nosotros go the current blitheness value (animatedValue) from our updateListener using the propertyName alleged before.
  5. Update the currentPercentage variable that is used to draw our inner arc on each onDraw call.
  6. Now we call for a view redraw after nosotros already updated the value.
  7. We run our blitheness.

Note: This animation will starting time only when the function animateProgress get chosen.

In lodge to trigger our new animation, nosotros'll demand to add a Button to our activity layout in order to perform start information technology when clicking the button.

                      // ...                                                          <Button
android:id="@+id/animateButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="animate"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progress" />
// ...

And add together a clickListener on our Activity class:

          animateButton.setOnClickListener            {
progress.animateProgress()
}

And there you go!

Concluding animation

Yous tin can observe the full code here.

Promise you enjoyed this post, yous tin follow me on twitter @paulnunezm where I normally tweet about Android Dev. And let delight permit me know what y'all recall in the annotate section bellow.

gravesfolady.blogspot.com

Source: https://medium.com/@paulnunezm/canvas-animations-simple-circle-progress-view-on-android-8309900ab8ed

0 Response to "Draw Circle in Canvas Android"

ارسال یک نظر

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel