1. Overview
This article is mainly about how to customize a time clock, through simple exercises can be a simple study of Android in the custom view of some of the common drawing techniques to optimize the Android graphics operation. To start with, look at the effect we need to achieve:
When we see this effect there should be some thinking in mind, we should break it down into the following steps:
1. Instrument panel (Round)
2, tick marks (long medium short)
3, tick value (1-12)
4. Pointer (time and seconds)
5. Move the pointer and compute the position of the pointer
Now that we have a clear idea of our own, then we come alone.
The first step:1, Custom View properties, first under the res/values/to create a attrs.xml, in which to define our attributes and declare our entire style.
<span style= "FONT-SIZE:14PX;" > <declare-styleable name= "Clockview" > <attr name= "Mradius format=" Dimension "/> <attr name=" mCi Rclecolor "format=" color "/> <attr name=" mcirclewidth "format=" Dimension "/> <attr name=" mtextsize "format
= "Dimension"/> <attr name= "mtextcolor" format= "Color"/> "<attr" name= "Mbigscalecolor" format= "Color"/> <attr name= "Mmiddlecalecolor" format= "color"/> <attr name= "msmallscalecolor" format= "Color"/> <att R name= "Mhourhandcolor" format= "color"/> <attr name= "mminutehandcolor" format= "color"/> <attr name= "MSec" Ondhandcolor "format=" color "/> <attr name=" mhourhandwidth "format=" Dimension "/>" <attr name= "MMinuteHandW" Idth "format=" Dimension "/> <attr name=" msecondhandwidth "format=" Dimension "/> </declare-styleable>&l T;/span>
We define the color and width of the clock's radius, background color, tick value (large, medium, small) and the pointer (time and seconds).
The custom class class is then Clockview and referenced in the mainactivity layout:
<span style= "FONT-SIZE:14PX;" > <com.dalong.customviewstudy.view.clockview
app:msecondhandcolor= "@color/coloraccent"
app: Mcirclecolor= "@android: Color/white"
app:mbigscalecolor= "@android: Color/black"
app:mmiddlecalecolor= "@ Android:color/black "
app:msmallscalecolor=" @color/coloraccent "
app:mhourhandcolor=" @android: color/ Black "
app:mminutehandcolor=" @android: Color/black "
app:mtextcolor=" @android: Color/black "
app: Mhourhandwidth= "13DP"
app:msecondhandwidth= "5DP"
app:mminutehandwidth= "8DP"
app:mtextsize= "16sp "
android:layout_centerinparent=" true "
android:layout_width=" Match_parent
android:layout_ height= "Match_parent"/></span>
2, in the custom view of the construction method, get our custom style
<span style= "FONT-SIZE:14PX;"
>//Text Brush object private Paint mtextpaint;
Circle, pointer, tick brush private Paint mpaint;
The radius is public float Mradius;
Outer circle Color public int mcirclecolor;
The width of the outer circle is public float mcirclewidth;
The size of the text is public float mtextsize;
The color of the text is public int mtextcolor;
Large scale color public int mbigscalecolor;
Medium scale public int mmiddlecalecolor;
Small scale color public int msmallscalecolor;
Clockwise color public int mhourhandcolor;
The minute hand color public int mminutehandcolor;
The second hand color public int msecondhandcolor;
The clockwise width is public float mhourhandwidth;
Minute hand width public float mminutehandwidth;
Second hand width public float msecondhandwidth;
Control width public int mwidth;
Control height public int mheght;
Public Clockview {This (context,null);
Public Clockview (context, AttributeSet attrs) {This (context, attrs,0); Public Clockview (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyleattr);
TypedArray typedarray=context.obtainstyledattributes (Attrs, R.styleable.clockview);
Mradius=typedarray.getdimension (r.styleable.clockview_mradius,400);
Mcirclecolor=typedarray.getcolor (R.styleable.clockview_mcirclecolor, Color.White);
Mcirclewidth=typedarray.getdimension (r.styleable.clockview_mcirclewidth,20);
Mtextsize=typedarray.getdimension (r.styleable.clockview_mcirclewidth,40);
Mtextcolor=typedarray.getcolor (R.styleable.clockview_mtextcolor,color.dkgray);
Mbigscalecolor=typedarray.getcolor (R.styleable.clockview_mbigscalecolor,color.black);
Msmallscalecolor=typedarray.getcolor (r.styleable.clockview_msmallscalecolor,color.red);
Mmiddlecalecolor=typedarray.getcolor (R.styleable.clockview_mmiddlecalecolor,color.black);
Mhourhandcolor=typedarray.getcolor (R.styleable.clockview_mhourhandcolor,color.black);
Mminutehandcolor=typedarray.getcolor (R.styleable.clockview_mminutehandcolor,color.black); Msecondhandcolor=typedarray.getcolor (R.styleable.clockview_msecondhandcolor,color.black);
Mhourhandwidth=typedarray.getdimension (r.styleable.clockview_mhourhandwidth,20);
Mminutehandwidth=typedarray.getdimension (r.styleable.clockview_mminutehandwidth,10);
Msecondhandwidth=typedarray.getdimension (r.styleable.clockview_msecondhandwidth,5);
Mpaint=new Paint ();
Mpaint.setantialias (TRUE);
Mpaint.setstyle (Paint.Style.STROKE);
Mtextpaint=new Paint ();
Mtextpaint.setantialias (TRUE);
Mtextpaint.setstyle (Paint.Style.STROKE);
Mtextpaint.settextsize (mtextsize);
Mtextpaint.setcolor (Mtextcolor);
} </span>
3, we rewrite the ondraw,onmesure call system provided:
Onmeure method
<span style= "FONT-SIZE:14PX;" > @Override
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
setmeasureddimension ( Measuresize (Widthmeasurespec), Measuresize (Heightmeasurespec));
private int measuresize (int mmeasurespec) {
int result;
int Mode=measurespec.getmode (MMEASURESPEC);
int size=measurespec.getsize (MMEASURESPEC);
if (mode==measurespec.exactly) {
result=size;
} else{
result=400;
if (mode==measurespec.at_most) {
result=math.min (result,size);
}
}
return result;
} </span>
OnDraw method
<span style= "FONT-SIZE:14PX;" > @Override
protected void OnDraw (Canvas Canvas) {
super.ondraw (Canvas);
Set the width-height, radius mwidth=getmeasuredwidth ()-getpaddingleft ()-getpaddingright ()
;
Mheght=getmeasuredheight ()-getpaddingbottom ()-getpaddingtop ();
Mradius=math.min (MWIDTH/2,MHEGHT/2);
First, the circular
drawcircle (canvas) is drawn;
Draw scale
Drawscale (canvas);
Draw pointer
drawpointer (canvas);
Send Message Refresh UI
handler.sendemptymessagedelayed (start_clock,1000);
}
</span>
One of the core codes is the three methods:
<span style= "FONT-SIZE:14PX;" > //First draw round
drawcircle (canvas);
Draw scale
Drawscale (canvas);
Draw pointer
First, let's start with the first method:
<span style= "FONT-SIZE:14PX;" >/**
* Draw round
* @param canvas
/
private void drawcircle (canvas canvas) {
mpaint.setstrokewidth ( Mcirclewidth);
Mpaint.setstyle (Paint.Style.FILL);
Mpaint.setcolor (Mcirclecolor);
Canvas.drawcircle (Mwidth/2,mheght/2,mradius,mpaint);
} </span>
This method is actually very simple for our brushes to set our custom style after the center as a circle, with our set radius to draw a circle, where the set is Paint.Style.FILL a solid. You can also set a hollow. Look at the effect we've done with this method:
Second method:
<span style= "FONT-SIZE:14PX;"
>/** * Scale and text * @param canvas * * private void Drawscale (canvas canvas) {for (int i=0;i<60;i++) { Set large scale if (i==0| | i==15| | i==30| |
i==45) {mpaint.setstrokewidth (6);
Mpaint.setcolor (Mbigscalecolor); Canvas.drawline (MWIDTH/2,MHEGHT/2-MWIDTH/2+MCIRCLEWIDTH/2, Mwidth/2,mheght/2-mwidth/2+mcirclewidth/2+60,mpaint)
;
String scaletv=string.valueof (I==0?12:I/5); Canvas.drawtext (Scaletv,mwidth/2-mtextpaint.measuretext (SCALETV)/2, mheght/2-mwidth/2+mcirclewidth/2+95,
Mtextpaint); }else if (i==5| | i==10| | i==20| | i==25| | i==35| | i==40| | i==50| |
I==55)//Set medium scale {mpaint.setstrokewidth (4);
Mpaint.setcolor (Mmiddlecalecolor); Canvas.drawline (MWIDTH/2,MHEGHT/2-MWIDTH/2+MCIRCLEWIDTH/2, Mwidth/2,mheght/2-mwidth/2+mcirclewidth/2+40,mpaint)
;
String scaletv=string.valueof (I/5); Canvas.drawtext (Scaletv,mwidth/2-mtextpaint.measuretext (SCALETV)/2, Mheght/2-mwidth/2+mcircleWidth/2+75,mtextpaint);
}else//Set Small scale {mpaint.setcolor (msmallscalecolor);
Mpaint.setstrokewidth (2);
Canvas.drawline (MWIDTH/2,MHEGHT/2-MWIDTH/2+MCIRCLEWIDTH/2, mwidth/2,mheght/2-mwidth/2+mcirclewidth+30,mpaint);
} canvas.rotate (6,MWIDTH/2,MHEGHT/2);
}}</span>
This method code does not seem to have much to do with a circle divided into 60 parts, because we have 60 ticks on the clock, which set 4 large scale for 0,15,30,45 respectively. Corresponding to the clock 12 points 3 points 6 points and 9 points, If you have any doubts about this place, you can look at your watch or clock to understand that, at the same time also set a 8 medium scale for 5,10,20,25,35,40,50,55, in fact, the corresponding is the 1,2,4,5,7,8,10,11 point. Here is the main oneself feel so clearly good-looking, if there is no obsessive-compulsive disorder you can directly set the big scale can be. Others are small scale, according to their own set in the attr color and size set the brush paint respectively to draw on it. Let's see how our effect has turned out this way:
The third method is to draw a pointer:
<span style= "FONT-SIZE:14PX;" >/** * Draw pointer * @param canvas/private void drawpointer (canvas canvas) {Calendar Mcalendar=calendar.get
Instance ();
Gets the current number of hours int hours = Mcalendar.get (Calendar.hour);
Gets the current number of minutes int minutes = Mcalendar.get (Calendar.minute);
Gets the current number of seconds int seconds=mcalendar.get (calendar.second);
Mpaint.setstrokecap (Paint.Cap.ROUND);
Draw the hour canvas.save ();
Mpaint.setcolor (Mhourhandcolor);
Mpaint.setstrokewidth (Mhourhandwidth); Here the calculation of the clockwise need to rotate the angle to achieve the principle is to calculate how many minutes divided by 60 to calculate the actual number of hours (with decimals, in order to more accurately calculate the degree), known 12 hours is 360 degrees, now find the actual number of hours to calculate the angle of the Float Hoursangle = (hours
* + minutes)/60f/12f * 360;
Canvas.rotate (Hoursangle, MWIDTH/2, MHEGHT/2);
Canvas.drawline (MWIDTH/2, MHEGHT/2-mwidth/2f*0.5f, MWIDTH/2, MHEGHT/2 + mwidth/2f*0.15f, mPaint);
Canvas.restore ();
Draw the minute hand canvas.save ();
Mpaint.setcolor (Mminutehandcolor);
Mpaint.setstrokewidth (Mminutehandwidth); Here, the minute hand needs to rotate the angle 60 minutes 360 degrees, to find out the actual number of minutes accounted for the degree FloaT minutesangle = (minutes*60+seconds)/60f/60f * 360;
Canvas.rotate (Minutesangle, MWIDTH/2, MHEGHT/2);
Canvas.drawline (MWIDTH/2, MHEGHT/2-mwidth/2f*0.7f, MWIDTH/2, MHEGHT/2 + mwidth/2f*0.15f, mPaint);
Canvas.restore ();
Draw the Middle Circle canvas.save ();
Mpaint.setcolor (Msecondhandcolor);
Mpaint.setstrokewidth (Msecondhandwidth);
Mpaint.setstyle (Paint.Style.FILL);
Canvas.drawcircle (Mwidth/2,mheght/2,20,mpaint);
Canvas.restore ();
Draw the second hand canvas.save ();
Mpaint.setcolor (Msecondhandcolor);
Mpaint.setstrokewidth (Msecondhandwidth);
Mpaint.setstyle (Paint.Style.STROKE);
Here the second hand needs to rotate the angle 60 seconds 360 degrees, to find the actual number of seconds accounted for the degree of Float secondangle = seconds/60f*360;
Canvas.rotate (Secondangle, MWIDTH/2, MHEGHT/2);
Canvas.drawline (MWIDTH/2, MHEGHT/2-mwidth/2f*0.8f, MWIDTH/2, MHEGHT/2 + mwidth/2f*0.2f, mPaint);
Canvas.restore ();
}</span>
In fact, I commented that this method has been written in detail, first of all we need to get to the current time, this is often written by everyone is not a problem. The main point is how to set the position of the seconds pointer is the key. Here I use a very ingenious method to make the drawing easier.
First look at the drawing hour:
<span style= "FONT-SIZE:14PX;" >//Draw clockwise
Canvas.save ();
Mpaint.setcolor (Mhourhandcolor);
Mpaint.setstrokewidth (mhourhandwidth);
Here the calculation of the clockwise need to rotate the angle to achieve the principle is to calculate how many minutes divided by 60 to calculate the actual number of hours (with decimals, in order to more accurately calculate the degree), known 12 hours is 360 degrees, now the actual number of hours to find the ratio of the angle
Float hoursangle = ( Hours + minutes)/60f/12f * 360;
Canvas.rotate (Hoursangle, MWIDTH/2, MHEGHT/2);
Canvas.drawline (MWIDTH/2, MHEGHT/2-mwidth/2f*0.5f, MWIDTH/2, MHEGHT/2 + mwidth/2f*0.15f, mPaint);
Canvas.restore ();</span>
The first three lines of code are not detailed, the Canvas.save method is to save all previously drawn pictures. Action on the new layer for subsequent operations. And Photoshop is a bit of a meaning. We all know that when we get to the current number of hours, we should directly point the hour to the corresponding time number? It's definitely not, like 3:30 the hour is the position between 3 and 4, right? So we need to get to the current number of minutes plus the number of hours is the real number of the current hour (in fact, the second hand also needs to be counted, but here is negligible, if you are more compulsive than I can add). When we know the actual number of hours, is very simple, because we know that a lap of 360 degrees on average 12 hours, this individual told me I do not know ah, if this common sense do not know, you go to the wall, so as long as 360/12* real hours is the need to rotate the angle. It's easy to think. Calculate the angle after the canvas.rotate rotation this angle in the drawing a straight line on OK, hahaha, is not so esey, other minute hand and second hand the same truth, here is not much to say, see the code directly can understand.
<span style= "FONT-SIZE:14PX;"
>//Draw the minute hand canvas.save ();
Mpaint.setcolor (Mminutehandcolor);
Mpaint.setstrokewidth (Mminutehandwidth);
Here the minute hand needs to rotate the angle 60 minutes 360 degrees, to find out the actual number of minutes of the degree of Float Minutesangle = (minutes*60+seconds)/60f/60f * 360;
Canvas.rotate (Minutesangle, MWIDTH/2, MHEGHT/2);
Canvas.drawline (MWIDTH/2, MHEGHT/2-mwidth/2f*0.7f, MWIDTH/2, MHEGHT/2 + mwidth/2f*0.15f, mPaint);
Canvas.restore ();
Draw the Middle Circle canvas.save ();
Mpaint.setcolor (Msecondhandcolor);
Mpaint.setstrokewidth (Msecondhandwidth);
Mpaint.setstyle (Paint.Style.FILL);
Canvas.drawcircle (Mwidth/2,mheght/2,20,mpaint);
Canvas.restore ();
Draw the second hand canvas.save ();
Mpaint.setcolor (Msecondhandcolor);
Mpaint.setstrokewidth (Msecondhandwidth);
Mpaint.setstyle (Paint.Style.STROKE);
Here the second hand needs to rotate the angle 60 seconds 360 degrees, to find the actual number of seconds accounted for the degree of Float secondangle = seconds/60f*360; Canvas.rotate (Secondangle, MWIDTH/2, MHEGHT/2);
Canvas.drawline (MWIDTH/2, MHEGHT/2-mwidth/2f*0.8f, MWIDTH/2, MHEGHT/2 + mwidth/2f*0.2f, mPaint);
Canvas.restore ();</span>
One of the circles in the middle of the draw is caused by my obsessive-compulsive disorder, I think the middle of a circle to look good point. This is what happens when we execute this method:
Haha, there's only one last step down, is to let the pointer move, right is to move, in fact, we also care about when we draw the pointer in the method directly to the current time set the position of the pointer, so as long as we get a timer to refresh the UI is done, Here's a hander to send an empty message.
Private Handler handler=new Handler () {
@Override public
void Handlemessage (msg) {
Super.handlemessage (msg);
Switch (msg.what) {
case Start_clock:
//update seconds and minutes
invalidate ();
Update
handler.sendemptymessagedelayed (start_clock,1000) every 1 seconds;
break;
}
}
;
It becomes the following effect:
Is it simple? Attached Github:https://github.com/dalong982242260/customviewstudy
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.