Today we implement a new control that inherits directly from the view. We all know the music player, in the click of a song to play, there will usually be a piece of area used to display the audio bar, we today to learn, the player audio bar implementation.
First we define a class, inherit directly from view, rewrite its construction method, and initialize a brush, which is the same as the previous section. Post the code directly:
public class Audiobar extends view{
private Paint mtextpaint;
Public Audiobar {This
(context,null);
}
Public Audiobar (context, AttributeSet attrs) {This
(context, attrs,0);
}
Public Audiobar (context, AttributeSet attrs, int defstyleattr) {
Super (context, attrs, defstyleattr);
Init ();
}
private void Init () {
mtextpaint = new Textpaint ();
Mtextpaint.setcolor (color.red);
}
And then again, to define our own view control, we need to rewrite the view's OnDraw () method.
@Override
protected void OnDraw (Canvas Canvas) {
super.ondraw (Canvas);
}
A partner who has heard or played music knows what the audio bar looks like, and nothing more than the different vertical graphs bouncing back and forth, where we know that we can do this with a vertical rectangle in our Android. Each rectangle is separated by a fixed spacing to simulate the implementation of our target control-audio bar. Post the code first, and wait for the code to explain:
@Override
protected void OnDraw (Canvas Canvas) {
super.ondraw (Canvas);
width = Getmeasuredwidth ();
Height = getmeasuredheight ();
int mrectcount = 0;
for (int count = 5; count < width; count = mrectwidth) {
mrectcount + +;
}
for (int i = 0; i < Mrectcount i + +) {
double mrandom = Math.random ();
Mrectheight = (float) (height * mrandom);
Canvas.drawrect (offset + mrectwidth * I,
mrectheight,
mrectwidth * (i+1),
height,
mtextpaint);
}
OK, look at this code, first of all we get the phone frequency screen size, and then I will be based on cell phone frequency screen size and predefined rectangular width (here using the Mrectwidth variable) to calculate the current phone frequency screen can accommodate how many rectangles (using Mrectcount to count). Then by looping through the creation of the rectangle, let the system draw us the view we defined. Of course, I also randomly generated a random number to control the height of the rectangle.
OK, add it to our layout file and show it in the activity to see what it does:
Activity_main.xml file
<?xml version= "1.0" encoding= "Utf-8"?> <linearlayout xmlns:android=
"http://schemas.android.com/apk/" Res/android "
xmlns:tools=" Http://schemas.android.com/tools "
android:layout_width=" Match_parent
" android:layout_height= "Match_parent"
android:orientation= "vertical"
tools:context= " Com.sanhuimusic.mycustomview.MainActivity ">
<com.sanhuimusic.mycustomview.view.audiobar
android: Layout_width= "Match_parent"
android:layout_height= "match_parent"
/>
</LinearLayout>
Then Mainactivity class
public class Mainactivity extends Appcompatactivity {
@Override
protected void OnCreate (Bundle Savedinstancestate) {
super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
}
Now run the program to see the effect.
Isn't it cool? But have a partner to have the question, the audio strip is not all dynamic? Now we are only a static rectangular bar ah, don't worry, we now let it move, but how to achieve it?
As experienced partners know, the UI views we use or define are displayed in the activity after the OnDraw () is finished, so is it possible for us to implement dynamic views without stopping the method? Is there any way to keep calling it to make it constantly drawn? The answer is obvious, using the invalidate () method, which can constantly redraw the view. Because of the use of invalidate (); the interval is too short and too fast, so depending on our requirements, we can redraw the view using the deferred method, where we use postinvalidatedelayed (500); Let it repaint 500 milliseconds, This will reflect the dynamic audio bar. We can try, the dynamic map is not very good, I do not map, you can run down the program.
OK, now basically meet our requirements, is not sent a sigh of relief, yet, have you tried to add padding properties to our custom controls in the layout file, try it. Haha, is there any change in wood?
That is because we did not take this into account in the OnDraw () method. In a custom control, when you inherit view directly, you must take into account the effect of the Padding property on the control, so next, let our controls close to the native controls.
@Override
protected void OnDraw (Canvas Canvas) {
super.ondraw (Canvas);
int leftpadding = Getpaddingleft ();
int toppadding = Getpaddingtop ();
int rightpadding = Getpaddingright ();
int bottompadding = Getpaddingbottom ();
width = getmeasuredwidth ()-leftpadding-rightpadding;
Height = getmeasuredheight ()-toppadding-bottompadding;
int mrectcount = 0;
for (int count = 5; count < width; count = mrectwidth) {
mrectcount + +;
}
for (int i = 0; i < Mrectcount i + +) {
double mrandom = Math.random ();
Mrectheight = (float) (height * mrandom);
Canvas.drawrect (offset + mrectwidth * I,
mrectheight,
mrectwidth * (i+1),
height,
mtextpaint);
postinvalidatedelayed (+);
}
Also quite good understanding, according to the current situation of the Padding property control on the OK, small partners now hurriedly in the run try it.
Here the entire custom control has almost finished, but the careful partner may discover: We make the audio bar can not occupy the entire frequency screen ah, hey, this is simpler, our usual practice is to modify the layout of the file does not do it, OK, modify the following:
Activity_main.xml file
<?xml version= "1.0" encoding= "Utf-8"?> <linearlayout xmlns:android=
"http://schemas.android.com/apk/" Res/android "
xmlns:tools=" Http://schemas.android.com/tools "
android:layout_width=" Match_parent
" android:layout_height= "Match_parent"
android:orientation= "vertical"
tools:context= " Com.sanhuimusic.mycustomview.MainActivity ">
<com.sanhuimusic.mycustomview.view.audiobar
android: Layout_width= "Wrap_content"
android:layout_height= "wrap_content"
/>
</LinearLayout>
OK, that's it, run it, try it.
I pour, how completely no wood has changed ah, check check, or wood has problems, in the end is which problem, I think you should be covered.
It's time for you to search or book a query, (10 seconds later, haha) by understanding you probably understand the problem, the view workflow is before OnDraw drawing, it is necessary to measure the layout, here introduced two nouns, measurement, and layout. I want to do a special section on the workflow of view, so now we just need to understand where the view measurement works.
Well, after querying the data, we learned that view measurement is done in the Onmeasure () method. So let's see how it's measured, and why we're using wrap_content under the current scenario. With the question, we first rewrite the view's Onmeasure () method, as follows:
@Override
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
super.onmeasure ( Widthmeasurespec, Heightmeasurespec);
Then follow to Super.onmeasure (Widthmeasurespec, heightmeasurespec); Source code, we see the source is very simple, such as the following,
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
setmeasureddimension (getdefaultsize ( Getsuggestedminimumwidth (), Widthmeasurespec),
getdefaultsize (Getsuggestedminimumheight (), HeightMeasureSpec ));
}
In the method body, only the Setmeasureddimension () method is invoked to determine the view size, and the parameters inside it are obtained by the Getdefaultsize () method to get the size, followed by the Getdefaultsize () method.
public static int getdefaultsize (int size, int measurespec) {
int = size;
int specmode = Measurespec.getmode (measurespec);
int specsize = measurespec.getsize (measurespec);
Switch (specmode) {case
measurespec.unspecified: result
= size;
break;
Case Measurespec.at_most: Case
measurespec.exactly: result
= specsize;
break;
return result;
}
OK, very simple source code, mainly through the Measurespec class (later will be explained in detail) to obtain the measurement of the pattern and measurement of the size, and then measured by the pattern to determine the size of the measurement, but one thing is not very strange, when the measurement mode is at_most (maximum mode, corresponding to the layout width high property is wrap_content), its measurement size and mode are exactly (exact value mode, corresponding to layout width high property is match_parent), as we suddenly realize, The default measurement size of the system is whether the layout width high property is Wrap_content or match_parent its value is the default value of Match_parent.
It is clear from this that we did not meet our expectations when we modified the layout value of the high attribute. So how do we solve this? It is also very simple, because the value of the view measurement depends on the method of Setmeasureddimension (), so as long as we rewrite the Setmeasureddimension () method, we can accomplish our requirements. Therefore, we can do the following:
@Override
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
super.onmeasure ( Widthmeasurespec, Heightmeasurespec);
int widthspecmode = Measurespec.getmode (widthmeasurespec);
int widthspecsize = measurespec.getsize (widthmeasurespec);
int heightspecmode = Measurespec.getmode (heightmeasurespec);
int heightspecsize = measurespec.getsize (heightmeasurespec);
if (Widthspecmode = = Measurespec.at_most && Heightspecmode = measurespec.at_most) {
setmeasureddimension ( Getmeasuredwidth ()/2, Getmeasuredheight ()/2);
else if (Widthspecmode = = measurespec.at_most) {
setmeasureddimension (Getmeasuredwidth ()/2, heightspecsize);
} else if (Heightspecmode = = measurespec.at_most) {
setmeasureddimension (widthspecsize, Getmeasuredheight ()/2);
}
}
Code Explanation: First we get the control measurement mode and size, and then according to the situation to identify the current view properties of what kind of scenario, and then rewrite the Setmeasureddimension () method according to the specific situation. Here I was let it show half of the screen. Well, let's see if it fits our needs now.
All right, it fits the demand, you can be happy.
Summary: When we directly inherit the view to implement the custom control, the main difficulty lies in the calculation of the coordinate system, the correct coordinates are calculated, the custom control is completed in half, and the padding properties and Layout_width and Layout_ are also needed. The Height property value is considered necessary for the wrap_content situation. All right, let's talk about it today.
The above is a small set to introduce the Andriod custom control of the audio bar, I hope to help you, if you have any questions please give me a message, small series will promptly reply to everyone. Here also thank you very much for the cloud Habitat Community website support!