Draw Circle Inside Rectangle Android
How to draw a custom view?
In Android SDK we can use a lot of useful predefined and gear up-to-go views like TextView, Button, CheckBox, ProgressBar and many others. However at that place are cases in which we take to do more than than just use one of them — we have to create a custom ane. If the view is very like to one of the provided with the Android platform, we can try to extend it and customize information technology in a proper manner that meets our expectations. But even so, the day volition come and there will be no escape — eventually nosotros'll demand 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 ain. But information technology turned out to not be that difficult. Let's try to implement one together.
Imagine that we demand to create a custom book bar. The first matter nosotros're going to exercise is to create a class that extends the View
.
Just ane 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 it's enough.
At present it's time to describe something! Let's start from a line.
How to draw a line?
To draw something, nosotros take to override the onDraw()
template method.
There is simply one parameter that this method gives us — Canvas. We'll be drawing on it. Merely how? Permit's see how the API for drawing looks similar.
Canvas gives as a lot of methods to draw something, like drawCircle()
, drawPath()
, drawRect()
and and then forth. Nosotros need a line, so we'll use drawLine()
.
The method takes five parameters:
- startX, startY — the point from which the line should starts,
- stopX, stopY — the signal of the stop of the line,
- pigment — the paint which we're using to describe the line.
The first 4 are pretty obvious and the last one nosotros'll embrace in a minute. First, we should care about the alarm.
Only put, we shouldn't create any new instances of objects within the onDraw()
method, because our UI won't exist smooth if we allocate a lot of new objects that eventually will exist garbage nerveless. We need to move creation of the Paint object out of this method.
The last matter is to add our view to the layout file.
At present allow'south run our projection and see the results!
Yeah! Nosotros've drawn a line 😊 But information technology'southward non centered as we wanted to. Actually our view takes the whole space. Probably considering we haven't specified how much space the view should accept. It's time to override onMeasure()
method.
Showtime, we demand to decode the mode and size of the view. Why? Permit's look at what the documentation of onMeasure()
says about these parameters.
Parameters:
widthMeasureSpec — horizontal space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.
heightMeasureSpec — vertical space requirements every bit imposed past the parent. The requirements are encoded with View.MeasureSpec.
Parent view passes these parameters in the encoded form, then nosotros need to decode them offset — it's probably connected with some kind of optimisations.
Then we demand to check the mode. There are 3 different modes:
- EXACTLY — when we set the exact dp value (like 300dp) on our view or it's
match_parent
, - AT_MOST — when it'south
wrap_content
, - UNSPECIFIED — when it doesn't affair, and a View can be as big as it want to be, considering i.e. parent is a ScrollView (and so the height in portrait manner is irrelevant).
You can play with it and check if it's true, for case past adding some logs within the onMeasure()
method and changing layout params.
So as we can encounter, we take the given dp value if it'southward provided, otherwise we take the default ones which are defined in the res/values/dimens.xml
resources file.
After all, think to call setMeasuredDimension()
method ⚠️ to apply the view dimensions.
Now let's change the parameters a scrap to have a horizontal line and run the project!
Absurd! Again, now you should play a bit with different layout_width
and layout_height
parameters to meet what's changing. Plow on Prove Layout Bounds option in Developer Options to see the exacts infinite that our view is taking. If you aren't familiar with this choice, you can find how to enable it for example in my article about margin and padding.
Ok, simply we want to have a thicker line, kind of a bar, and so we'll exist able to manipulate its superlative besides every bit the width. Let'south change the line to the rectangle
How to draw a rectangle?
Fortunately it's pretty easy with our example. All nosotros need to do is to modify drawLine()
method to drawRect()
and apply the height value instead of 0.0F to the lesser
parameter. Nosotros should also refactor the name of the linePaint
to barPaint
.
Let's besides change the volume_bar_default_height
to 12dp and run the project.
Now we want to change a color, let's say, to greyness. But there is no colour parameter on the drawRectangle()
method. And it shouldn't be, considering through the Canvas nosotros're saying what to draw, however we use the Paint class to say how we're going to practise this. And so we'll apply our barPaint
to change the color.
The adjacent stride is to draw a circumvolve that will show the current volume level.
How to describe a circle?
To practice this nosotros'll use drawCircle()
method and nosotros'll create a new Paint object to ready a dissimilar color for the circle.
For now we've centered information technology (the center indicate of our circle is a half of the bar width and one-half of the top) and we fix the radius to fit the acme of the bar.
Now information technology's fourth dimension to react on the book level changes and change the circumvolve position.
How to react on the book level changes?
Before we'll be changing our view dynamically, let's prepare the current volume level when the MainActivity
view is created.
We're using AudioManager
course to retrieve volume levels — the maximum levels count and the current 1. Android has a couple of dissimilar volume streams similar STREAM_ALARM for defining volume level for alarms or STREAM_MUSIC for setting it for music. Yous can see different streams when you press the volume button and aggrandize the list.
Nosotros're using STREAM_SYSTEM because when we run our app that's the default ane that will be irresolute when we hit one of the book buttons.
Permit'due south see what is inside the calibrateVolumeLevels()
method.
Nosotros've only saved the parameters and telephone call invalidate()
method which volition phone call onDraw()
. In the second one we have to do some calculations to describe the circle correctly.
To make clean the lawmaking a chip we've extracted drawing the bar and drawing the pollex to separate methods. drawThumb()
is actual the one with the new calculations. We didn't change the Y or radius values, just the X 1 considering we want to move our pollex on the horizontal axis.
All we have to do is to divide the width
of our bar by the volume levels count and multiply information technology past the current volume level. So for example if our volume bar width is 700, the book level count is 7 and the electric current one is 5, the method returns 500.
These two volume values unfortunately can be nix because we're non certain if the calibrateVolumeLevels()
method was called. We also have to store the values in the local ones considering in that location is a probability of a race status — volumeLevelsCount
and currentVolumeLevel
are mutable backdrop and they tin be changed right after checking is they are non null.
Let's see if we calibrate our view correctly.
It seems that it's working. Simply not exactly every bit we wanted to… Before I'll bear witness y'all the problem, allow'southward implement changing the circle positions whenever the volume is changed.
In the MainActivity
nosotros've overridden the dispatchKeyEvent()
method. We don't want to eat the event so false is returned and the super method is chosen as a outset matter. Thanks to that the volume is changed and we tin can recall the current level from the AudioManager
.
Setting the current volume level on VolumeBarView
is pretty simple because we're just updating the belongings and invalidate the view.
Allow'due south run the project and set up the volume to min or max level. I've made the view bigger so we'll see it more clearly.
On the edges nosotros encounter just the half of the thumb. That's considering we're drawing the center of the circle starting with the left border — on the correct side information technology's the same problem. Hmm… All we need is a half of the circle on the left side and some other half on the right side, kind of. And so perhaps nosotros should merely subtract the circle size (elevation of the volume bar) from the width and at the end of calculations simply move the circumvolve by half of its size? Let's implement this and see if it helped.
Now the calculations are done correctly. Our custom volume bar is working!
You can notice the whole code on the GitHub Repo.
Conclusion
Implementing a custom view is a challenge at the beginning. Complicated calculations can discourage us easily from doing it and that'south why in this article we've implemented a very simple version of custom volume bar. It's not that delightful as you might thought when you started reading this but it's just a start. We've learned basics and now nosotros can customize it further and I encourage you to practice this. Hope this article was helpful.
Best!
Bonus!
If you lot want to see more 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 "Draw Circle Inside Rectangle Android"
Publicar un comentario