Android to build your own time clock _android

Source: Internet
Author: User
Tags drawtext getcolor int size time and seconds

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.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.