[Android] Custom Lite Calendar Control

Source: Internet
Author: User
Tags drawtext gety

Let's take a look and see if the big boys want it:

Special features are not many, the focus is to explain how to construct a simple calendar, if the project is anxious to use, it is best to find someone else to write a calendar (additional sliding change calendar date and other functions)


---------------------------------------------------------------------------------------Gorgeous split-line---------------------------- ---------------------------------------------------------


The Month view is displayed based on the year and month you enter, and you can listen for a click of the date, which is what the calendar needs to implement.

As always, when we get a demand, do not worry about the code, first think about the implementation of the function is divided into how many parts, and then step by step to achieve, here, I roughly divided it into the following several functions:

1. Obtain the date distribution of a month;

2, the date of the distribution of the painting on the canvas;

3, listen to the date click event.

I see the function is not much, also three, the following will be a step-by-step explanation:


(1) Get the date distribution for a given month

In the implementation of this function, I chose the Calendar class, translation is the date class, it is an abstract class, but it provides the following methods let us get the calendar value, for example, get the following calendar values:

int year = Calendar.getinstance (). get (Calendar.year);//get current years int month = Calendar.getinstance (). Get (Calendar.month) + 1;//+1 is because the returned value does not represent the month, but rather corresponds to the value of the Calendar.may constant,//the calendar's constant value on the month starts with Calendar.january 0, to Calendar.december 11int DayOfMonth = Calendar.getinstance (). get (Calendar.day_of_month);//Gets the current time for the first day of the month int dayOfWeek = Calendar.getinstance (). get (Calendar.day_of_week);//Gets the current time for the day ordinal of the week (note that the first day of the week is Sunday, with a value of 1)
In fact, the use of the above is sufficient to achieve the functions we need in this part.

However, the above code is to obtain the calendar class of the day, so the date obtained is this day, if we want to see the date before or after the date, this will require us to manually change it:

Calendar calendar = Calendar.getinstance (); Calendar.set (year, month, day);

If we calendar.set (year, month, day), the day in is set to 1, then you can pass int dayOfWeek = Calendar.get (Calendar.day_of_week); Way to get the first day of the month is a few weeks, so the first part of the function we want to solve is complete!

Well? Don't understand? It seems to be a bit fast, I'll say it again:

The number of days per month is almost fixed (except that February of leap year becomes 29), both (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

So we can clearly determine the number of days of the month through the month, and then, if we know the first day of the month, and then add the number of days after that, until the number of days in this month is filled, then we can know the date of the month has been arranged. For example:

Specific implementation code, I encapsulated a bit, we can refer to: Dateutil.java

Call public static int[][] Getmonthnumfromdate (int year, int month) method to get the calendar date array, you can output the test to see

Package Com.xiaoyan.mycalendar;import java.util.calendar;/** * For processing Date Tool class * * @author Xiejinxiong * */public class Dateut Il {/** * Gets the current year * * @return */public static int getYear () {return calendar.getinstance (). get (Calendar.year);} /** * Gets the current month * * @return */public static int getMonth () {return calendar.getinstance (). Get (Calendar.month) + 1;//+1 is because the return The value that comes is not the month, but the value that corresponds to the Calendar.may constant,//the constant value of calendar on the month is 0 from Calendar.january, to Calendar.december 11}/** * Gets the current time for the day ordinal of the month * * @return */public static int getcurrentmonthday () {return calendar.getinstance (). Get (Calendar.day_of_ MONTH);} /** * Gets the current time for the day ordinal of the week * * @return */public static int getweekday () {return calendar.getinstance (). Get (Calendar.day_of_week );}  /** * Gets the current time for how many points of the day * * @return */public static int gethour () {return calendar.getinstance (). get (Calendar.hour_of_day);// Calendar calendar = calendar.getinstance ();//System.out.println (Calendar.get (calendar.hour_of_day)); 24-hour System//System.out.println (Calendar.get (Calendar.hour)); 12Hour System}/** * Gets the current minute time * * @return */public static int Getminute () {return calendar.getinstance (). get (Calendar.minute);} /** * To determine the date distribution for the month by obtaining the year and month * * @param years * @param month * @return */public static int[][] getmonthnumfromdate (int, I NT month) {Calendar calendar = calendar.getinstance (); Calendar.set (year, month-1, 1);/-1 is because the assigned value does not represent the month, Instead, the value corresponding to the Calendar.may constant, int days[][] = new int[6][7];//stores the month's date distribution int firstdayofweek = Calendar.get (Calendar.day_of_week) ;//Get the first day of the Month on the week (note that the first day of the week is Sunday, with a value of 1) int monthdaysnum = Getmonthdaysnum (year, month);//Get the number of days of the month//get the number of days of last month int Lastmonthdaysnum = Getlastmonthdaysnum (year, month);//Fill this month's date int daynum = 1;int Lastdaynum = 1;for (int i = 0; I < day S.length; i++) {for (int j = 0; J < Days[i].length; J + +) {if (i = = 0 && J < firstDayOfWeek-1) {//fill the remainder of last month days[i][ J] = Lastmonthdaysnum-firstdayofweek + 2 + j;} else if (daynum <= monthdaysnum) {//fill this month days[i][j] = daynum++;} else {//fill in future parts of next month days[i][j] = lastdaynum++;}}} Return Days;} /** * Number of days last month based on years and months * @param year * @param month * @return */public static int getlastmonthdaysnum (int, int mo nth) {int lastmonthdaysnum = 0;if (Month = = 1) {Lastmonthdaysnum = Getmonthdaysnum (year-1);} else {Lastmonthdaysnum = Getmonthdaysnum (year, month-1);} return lastmonthdaysnum;} /** * The number of days of the month based on the number of years and months * * @param year * @param month * @return If return is negative one, this indicates that the number of years and months entered does not conform to specifications */public static int getmonthdaysn Um (int, int month) {if (Year < 0 | | month <= 0 | | month > 12) {//For a simple judgment of the years and months return-1;}  Int[] Array = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//year, number of days per month if (Month! = 2) {return array[month-1];} else {if (year% 4 = = 0 && Year% = 0 | | year% 400 = = 0) {//Leap year judgment return;} else {return 28;}}}


(2) Draw a date distribution on the canvas

First, let's Review the basics:

Paint Painttext = new paint ();p ainttext.settextsize (+);p Ainttext.setcolor (Color.Black); Canvas.drawtext ("25", 100, , Painttext);
From the above code you can draw a number:

However, this is still not possible, because when painting the text, it is not the center of the painting as the center of the drawing, but in the center of the upper right of the point. (Well, it seems a little hard to see, I add two lines to compare:)

Paint Painttext = new paint ();p ainttext.settextsize (+);p Ainttext.setcolor (Color.Black); Canvas.drawtext ("25", 100, (Painttext), Canvas.drawline (0, +, Painttext, Painttext), Canvas.drawline (0, (+), (+);

It is very obvious that if we do not change the date figures on the painting, we will find that the number of calendar table is right, in order to eliminate this problem, we need to know the width of the text drawn, it is easy to offset it properly:

A. Get the width of the text:

Painttext.measuretext ("25");

B. Get the height of the text:

FontMetrics fm = painttext.getfontmetrics (), Float fontheight = (float) math.ceil (fm.descent-fm.top)/2;

From the above, we can easily center the number in the display:

Paint Painttext = new paint ();p ainttext.settextsize (+);p Ainttext.setcolor (Color.Black); FontMetrics fm = painttext.getfontmetrics (), Float fontheight = (float) math.ceil (fm.descent-fm.top)/2;canvas.drawtext ("100-painttext.measuretext",/2f, 100+FONTHEIGHT/2, Painttext), Canvas.drawline (0, +, (+), painttext); Canvas.drawline (0, Max, painttext);

OK, the problem with the center of the number is resolved, but the size of the calendar table is not yet determined, and you need to dynamically get the size of the control to calculate the table size:

@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//TODO auto-generated method Stubsuper.onmeasure (Widthmeasurespec, heightmeasurespec);//gain Control width = getmeasuredwidth ();// Calculate Calendar Table Width datenumwidth = width/7.0f;//Calculate Calendar Height height = (int) (Datenumwidth * 6);//Set Control width height setmeasureddimension (width, height );}
OK, the important things you need to get, now just according to the obtained calendar array, to traverse the drawing date number. The same, I also carry out encapsulation, we can also refer to:

Package Com.example.calendartest;import Android.content.context;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.paint.fontmetrics;import Android.util.attributeset;import Android.view.view;public class Calendarviewtest extends View {/** * uses enumerations to represent date states (today, this month, Not this month) * * @author Xiejinxiong * */public static enum Calendarstate {TODAY, current_month, no_current_month}/** screen width */pri vate int width;/** screen height */private int height;/** Day Group */private int[][] datenum;/** calendar date state array */private calendarstate[][] C alendarstates;/** year */private int year;/** month */private int month;/** painting class */private Drawcalendar drawcalendar;/** Calendar Table Width */ Private float Datenumwidth;public calendarviewtest (context context, AttributeSet attrs, int defstyle) {Super (context, Attrs, Defstyle); Initui (context);} Public Calendarviewtest (context context, AttributeSet Attrs) {Super (context, attrs); Initui (context);} Public Calendarviewtest (Context context) {super (context);Itui (context);} /** * Initialize UI * * @param context */private void Initui (Context context) {//Initialize date year = Dateutil.getyear (); month = Dateutil . GetMonth (); calendarstates = new Calendarstate[6][7];d Rawcalendar = new Drawcalendar (year, month);} /** * Set calendar time and Refresh Calendar view * * @param year * @param month */public void Setyearmonth (int year, int month) {this.year = Year;this . month = Month;drawcalendar = new Drawcalendar (year, month); invalidate ();} @Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//TODO auto-generated method Stubsuper.onmeasure (Widthmeasurespec, heightmeasurespec);//gain Control width = getmeasuredwidth ();// Calculate Calendar Table Width datenumwidth = width/7.0f;//Calculate Calendar Height height = (int) (Datenumwidth * 6);//Set Control width height setmeasureddimension (width, height );} @Overrideprotected void OnDraw (canvas canvas) {//TODO auto-generated method Stubsuper.ondraw (canvas); Drawcalendar.drawcalendarcanvas (canvas);} /** * Package Painting Calendar Method Painting class * * @author Xiejinxiong * */class drawcalendar {/** painting date brush */private PainT mpainttext;/** painting this day's blue circle background brush */private paint mpaintcircle;/** font height */private float fontheight;public drawcalendar (int ye AR, int month) {//Get the Month date arrangement array datenum = Dateutil.getmonthnumfromdate (year, month);//The brush that initializes the drawing text Mpainttext = new paint (); MP Ainttext.settextsize (+); Mpainttext.setcolor (Color.gray);//Set Gray Mpainttext.setantialias (TRUE);//Set the brush's jagged effect. Get font height fontmetrics fm = mpainttext.getfontmetrics () Fontheight = (float) math.ceil (fm.descent-fm.top)/2;//Initialize painting circle Pen mpaintcircle = new Paint (); Mpaintcircle.setcolor (Color.argb (100, 112, 199, 244));//Set Blue Mpaintcircle.setantialias ( true);//sets the brush's jagged effect. }/** * Painting Calendar * * @param canvas */public void Drawcalendarcanvas (canvas canvas) {//Canvas.drawcircle (WIDTH/2, WIDTH/2, wid  TH/2, Mpaint);//Draw round for (int i = 0; i < datenum.length; i++) {for (int j = 0; J < Datenum[i].length; J + +) {if (i = = 0 && Datenum[i][j] > 20) {//Last month's date Drawcalendarcell (i, J, Calendarstate.no_current_month,canvas);} else if ((i = = 5 | | i = = 4) && daTENUM[I][J] < 20) {//next month's date Drawcalendarcell (i, J, Calendarstate.no_current_month,canvas);} else {//month date if (datenum[ I][J] = = Dateutil.getcurrentmonthday ()) {//Is today's date number if (year = = Dateutil.getyear () && month = = Dateutil.getmonth ()) {//Whether it is this month Drawcalendarcell (i, J, Calendarstate.today,canvas);} Drawcalendarcell (i, J, Calendarstate.current_month,canvas);} else {Drawcalendarcell (i, J, Calendarstate.current_month,canvas);}}}}            /** * Painting Calendar Table * * @param i * horizontal serial number * @param J * Column ordinal * @param state * Status * @param canvas * Canvas */private void Drawcalendarcell (int i, int j, calendarstate State,canvas canvas) {switch (state) {Case today: Today calendarstates[i][j] = Calendarstate.today;mpainttext.setcolor (color.white); Canvas.drawcircle (DateNumWidth * j + datenumwidth/2,datenumwidth * i + DATENUMWIDTH/2, datenumwidth/2,mpaintcircle) break;case CURRENT_MONTH://this month Calen DARSTATES[I][J] = Calendarstate.current_month;mpainttext.setcolor (color.black); bReak;case no_current_month://not this month calendarstates[i][j] = Calendarstate.no_current_month;mpainttext.setcolor ( Color.gray); break;default:break;}  Painting Date Canvas.drawtext (Datenum[i][j] + "", Datenumwidth * j + datenumwidth/2-Mpainttext.measuretext (DateNum[i][j] + "") /2,datenumwidth * i + DATENUMWIDTH/2 + fontheight/2.0f,mpainttext);}}
(3) Monitor Date Click event

Listen to the date click is relatively simple, as long as we listen to the location of the click (x, y), and then divide the location by the width of the calendar table, you can get the Calendar table array i,j subscript, thus, it is easy to get the date clicked.

However, it is important to note that the position of the finger down and the position of the finger may be somewhat different, so we need to set a distance, within a suitable distance, that we can think of as a click event. When I set this distance, I used the viewconfiguration.get (context). Getscaledtouchslop (), which is the minimum distance to slide, because the general calendar has the ability to slide, using that distance, you can avoid conflicts with sliding events.

Of course, just listening is not enough, we have to provide a callback interface for the user to use, easy to execute the Click event related code.

Touchslop = Viewconfiguration.get (context). Getscaledtouchslop ();

@Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case motionevent.action_down:// Record the clicked coordinates Touchx = Event.getx (); touchy = Event.gety (); break;case MotionEvent.ACTION_UP:float touchlastx = Event.getx (); float touchlasty = event.gety (); if (Math.Abs (TOUCHLASTX-TOUCHX) < touchslop&& math.abs (touchlasty-touchy) & Lt  Touchslop) {//To determine whether it fits the normal click//calculates the clicked array sequence int datenumx = (int) (touchlastx/datenumwidth); int datenumy = (int) (Touchlasty/ Datenumwidth);//Use the callback function to respond by clicking on the calendar date Oncalendarclicklistener.oncalendaeclick (Datenum[datenumy][datenumx], CALENDARSTATES[DATENUMY][DATENUMX]);} Break;default:break;} return true;}
/** * Calendar Listener class *  * @author Xiejinxiong *  */public interface Oncalendarclicklistener {/** * calendar date Tap Listen *  * @param da Tenum *            Date number * @param calendarstate *            date State */public void Oncalendaeclick (int datenum, calendarstate calendarstate );}

By the above, you should be able to make your own ideas about the calendar, and you can design your own custom calendars as you like.

Source: http://download.csdn.net/detail/u011596810/9478962









[Android] Custom Lite Calendar Control

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.