How to Draw a Circle in Android
How to describe a custom view?
In Android SDK nosotros tin can use a lot of useful predefined and set-to-become views similar TextView, Button, CheckBox, ProgressBar and many others. However there are cases in which we have to do more than only employ one of them — we take to create a custom 1. If the view is very similar to 1 of the provided with the Android platform, we can try to extend it and customize it in a proper manner that meets our expectations. Only withal, the twenty-four hour period will come and in that location will be no escape — eventually we'll need to create a totally custom view from the scratch.
I was always terrified at the very thought of extending a View
class and implementing everything on my own. Merely it turned out to not be that hard. Let's effort to implement one together.
Imagine that we need to create a custom volume bar. The first thing nosotros're going to do is to create a class that extends the View
.
Just one constructor is overridden. The 1 that we're using when we're creating a view from the xml file. For the purpose of the article information technology's plenty.
At present it's time to depict something! Let's start from a line.
How to depict a line?
To describe something, we have to override the onDraw()
template method.
At that place is only one parameter that this method gives the states — Canvas. We'll be drawing on information technology. Simply how? Let'south see how the API for drawing looks similar.
Canvass gives as a lot of methods to describe something, like drawCircle()
, drawPath()
, drawRect()
and so forth. We need a line, so nosotros'll apply drawLine()
.
The method takes five parameters:
- startX, startY — the point from which the line should starts,
- stopX, stopY — the indicate of the end of the line,
- pigment — the pigment which we're using to describe the line.
The first four are pretty obvious and the last one we'll encompass in a minute. Starting time, we should care nearly the warning.
Merely put, we shouldn't create whatsoever new instances of objects inside the onDraw()
method, because our UI won't be smooth if we allocate a lot of new objects that eventually will exist garbage collected. Nosotros demand to move creation of the Paint object out of this method.
The last thing is to add our view to the layout file.
Now allow'due south run our project and see the results!
Aye! We've fatigued a line 😊 Just information technology's non centered as we wanted to. Actually our view takes the whole infinite. Probably because we haven't specified how much space the view should have. It's time to override onMeasure()
method.
Commencement, we need to decode the mode and size of the view. Why? Let's look at what the documentation of onMeasure()
says about these parameters.
Parameters:
widthMeasureSpec — horizontal infinite requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.
heightMeasureSpec — vertical space requirements every bit imposed by the parent. The requirements are encoded with View.MeasureSpec.
Parent view passes these parameters in the encoded form, and then we need to decode them first — it'due south probably continued with some kind of optimisations.
Then we demand to cheque the mode. In that location are 3 unlike modes:
- EXACTLY — when we set the exact dp value (similar 300dp) on our view or it'south
match_parent
, - AT_MOST — when information technology'southward
wrap_content
, - UNSPECIFIED — when it doesn't thing, and a View can be as big as it desire to be, because i.e. parent is a ScrollView (then the top in portrait way is irrelevant).
You can play with it and check if it's true, for example by calculation some logs inside the onMeasure()
method and changing layout params.
Then as nosotros can see, we accept the given dp value if it's provided, otherwise nosotros take the default ones which are defined in the res/values/dimens.xml
resource file.
Later all, remember to call setMeasuredDimension()
method ⚠️ to apply the view dimensions.
Now allow's change the parameters a bit to accept a horizontal line and run the projection!
Cool! Once more, at present you should play a scrap with unlike layout_width
and layout_height
parameters to see what's irresolute. Turn on Bear witness Layout Bounds selection in Developer Options to see the exacts space that our view is taking. If you lot aren't familiar with this option, you can detect how to enable it for example in my article about margin and padding.
Ok, just we want to accept a thicker line, kind of a bar, and so nosotros'll exist able to manipulate its height as well every bit the width. Let's change the line to the rectangle
How to draw a rectangle?
Fortunately it'due south pretty easy with our example. All we need to practise is to change drawLine()
method to drawRect()
and apply the height value instead of 0.0F to the bottom
parameter. Nosotros should also refactor the name of the linePaint
to barPaint
.
Let's besides modify the volume_bar_default_height
to 12dp and run the projection.
Now we desire to change a colour, let's say, to greyness. But in that location is no color parameter on the drawRectangle()
method. And it shouldn't be, because through the Canvas we're maxim what to draw, nonetheless we utilise the Pigment class to say how we're going to do this. So nosotros'll use our barPaint
to alter the color.
The adjacent footstep is to depict a circle that volition show the current book level.
How to draw a circle?
To practice this we'll use drawCircle()
method and we'll create a new Paint object to set a unlike color for the circle.
For now we've centered it (the center point of our circle is a half of the bar width and one-half of the height) and we set the radius to fit the meridian of the bar.
At present information technology's fourth dimension to react on the volume level changes and change the circle position.
How to react on the book level changes?
Earlier we'll be irresolute our view dynamically, permit'south set the current volume level when the MainActivity
view is created.
We're using AudioManager
form to recall volume levels — the maximum levels count and the current 1. Android has a couple of different volume streams like STREAM_ALARM for defining volume level for alarms or STREAM_MUSIC for setting it for music. You can see dissimilar streams when yous press the volume button and aggrandize the listing.
We're using STREAM_SYSTEM considering when we run our app that's the default one that will be changing when we striking one of the volume buttons.
Let's see what is within the calibrateVolumeLevels()
method.
Nosotros've merely saved the parameters and call invalidate()
method which volition telephone call onDraw()
. In the 2nd i nosotros have to practise some calculations to draw the circle correctly.
To clean the lawmaking a flake we've extracted cartoon the bar and cartoon the thumb to divide methods. drawThumb()
is actual the one with the new calculations. We didn't modify the Y or radius values, just the X one because we want to move our thumb on the horizontal axis.
All we have to practice is to divide the width
of our bar by the volume levels count and multiply information technology by the current volume level. So for example if our volume bar width is 700, the volume level count is 7 and the electric current i is 5, the method returns 500.
These two volume values unfortunately can be zero because we're not sure if the calibrateVolumeLevels()
method was called. We also take to store the values in the local ones because there is a probability of a race condition — volumeLevelsCount
and currentVolumeLevel
are mutable properties and they can be changed right after checking is they are not zip.
Allow's meet if we calibrate our view correctly.
It seems that it'southward working. Only not exactly equally nosotros wanted to… Before I'll show you the problem, let's implement changing the circumvolve positions whenever the volume is changed.
In the MainActivity
nosotros've overridden the dispatchKeyEvent()
method. We don't want to consume the event so false is returned and the super method is called as a start thing. Cheers to that the book is inverse and we can retrieve the current level from the AudioManager
.
Setting the current volume level on VolumeBarView
is pretty unproblematic because we're just updating the property and invalidate the view.
Let'due south run the projection and set the volume to min or max level. I've made the view bigger and then we'll encounter it more than clearly.
On the edges we encounter just the half of the thumb. That'south considering we're drawing the center of the circumvolve starting with the left edge — on the correct side it's the same problem. Hmm… All nosotros demand is a one-half of the circle on the left side and another half on the correct side, kind of. And then perchance we should but subtract the circle size (summit of the volume bar) from the width and at the end of calculations just movement the circle by one-half of its size? Let's implement this and meet if it helped.
Now the calculations are done correctly. Our custom volume bar is working!
Y'all tin can find the whole lawmaking on the GitHub Repo.
Conclusion
Implementing a custom view is a challenge at the kickoff. Complicated calculations can discourage us easily from doing it and that's why in this article nosotros've implemented a very simple version of custom volume bar. It's not that delightful every bit you might thought when you started reading this but it'due south simply a get-go. Nosotros've learned basics and now we tin can customize it further and I encourage you to exercise this. Hope this article was helpful.
Best!
Bonus!
If you want to meet more than delightful version of this custom volume bar, you can switch to the delightful branch on the repo that I've mentioned.
Source: https://proandroiddev.com/how-to-draw-a-custom-view-9da8016fe94
0 Response to "How to Draw a Circle in Android"
Post a Comment