【无私分享】干货!!!一个炫酷的自定义日历控件,摆脱日历时间选择烦恼,纯福利~

最近公司项目中有一个按日期查看信息的功能,楼主本想用之前用的wheelView将就使用的,不过产品经理有个新要求,就是点击按钮弹出的日期选择对话框必须显示农历节假日,周几什么的。这可就难为人了,倘若使用之前的滚动时间选择器,无疑是难以实现的,楼主辗转反侧,冥思苦想,却不得正果。

好吧,去网上下了几个OA系统一用就有了idea,突然想到手机自带的日历~~,oh,year,日历就有这功能,瞧瞧,我靠,这个东西,咋做。

仔细一瞧,似乎用GridView可以实现,额,二话不说就开干。折腾了半天都没弄好,而且界面贼丑,并且特别是国历和公历上面如何一一对应呢?

遇上楼主上google科普了一番,发现网上自定义日历不少,可是没有楼主想要的,好不容易找到一个功能齐全,可惜代码调了半天也用不起,好吧,只能一步一个脚印慢慢做。

终于功夫不负有心人,最终楼主还是弄出来一个雏形。

额,对,基本实现了日历功能,并能自动定位当前日期以及本月和非本月日期显示的不同,而且支持左右滑动哦~~

额,有图有真相。

最后,楼主把Demo分离了出来,供大家分享参阅。

view包下几个东西。

1)CalendarGridView.java

 1 package com.example.nanchen.mydateviewdemo.view;
 2
 3 import android.content.Context;
 4 import android.graphics.Color;
 5 import android.view.Gravity;
 6 import android.widget.GridView;
 7 import android.widget.LinearLayout;
 8
 9 /**
10  *
11  * 用于生成日历展示的GridView布局
12  *
13  * @author nanchen
14  * @date 16-8-10 上午11:35
15  */
16 public class CalendarGridView extends GridView {
17     /**
18      * 当前操作的上下文对象
19      */
20     private Context mContext;
21
22     /**
23      * CalendarGridView 构造器
24      *
25      * @param context
26      *            当前操作的上下文对象
27      */
28     public CalendarGridView(Context context) {
29         super(context);
30         mContext = context;
31         initGirdView();
32     }
33
34     /**
35      * 初始化gridView 控件的布局
36      */
37     private void initGirdView() {
38         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
39                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
40         setLayoutParams(params);
41         setNumColumns(7);// 设置每行列数
42         setGravity(Gravity.CENTER_VERTICAL);// 位置居中
43         setVerticalSpacing(1);// 垂直间隔
44         setHorizontalSpacing(1);// 水平间隔
45         setBackgroundColor(Color.argb(0xff, 0xe3, 0xee, 0xf4));
46
47         int i = mContext.getResources().getDisplayMetrics().widthPixels / 7;
48         int j = mContext.getResources().getDisplayMetrics().widthPixels
49                 - (i * 7);
50         int x = j / 2;
51         setPadding(x, 0, 0, 0);// 居中
52     }
53 }

2)

  1 package com.example.nanchen.mydateviewdemo.view;
  2
  3 import android.content.Context;
  4 import android.graphics.Color;
  5 import android.util.Log;
  6 import android.view.Gravity;
  7 import android.view.View;
  8 import android.view.ViewGroup;
  9 import android.view.ViewGroup.LayoutParams;
 10 import android.widget.BaseAdapter;
 11 import android.widget.LinearLayout;
 12 import android.widget.TextView;
 13
 14 import com.example.nanchen.mydateviewdemo.R;
 15
 16 import java.text.SimpleDateFormat;
 17 import java.util.ArrayList;
 18 import java.util.Calendar;
 19 import java.util.Date;
 20 import java.util.List;
 21 import java.util.Locale;
 22
 23 /**
 24  * @author nanchen
 25  * @date 16-8-10 上午11:35
 26  */
 27 public class CalendarGridViewAdapter extends BaseAdapter {
 28     /** 日历item中默认id从0xff0000开始 */
 29     private final static int DEFAULT_ID = 0xff0000;
 30     private Calendar calStartDate = Calendar.getInstance();// 当前显示的日历
 31     private Calendar calSelected = Calendar.getInstance(); // 选择的日历
 32
 33     /** 标注的日期 */
 34     private List<Date> markDates;
 35
 36     private Context mContext;
 37
 38     private Calendar calToday = Calendar.getInstance(); // 今日
 39     private ArrayList<Date> titles;
 40
 41     private ArrayList<java.util.Date> getDates() {
 42
 43         UpdateStartDateForMonth();
 44
 45         ArrayList<java.util.Date> alArrayList = new ArrayList<java.util.Date>();
 46
 47         for (int i = 1; i <= 42; i++) {
 48             alArrayList.add(calStartDate.getTime());
 49             calStartDate.add(Calendar.DAY_OF_MONTH, 1);
 50         }
 51
 52         return alArrayList;
 53     }
 54
 55     // construct
 56     public CalendarGridViewAdapter(Context context, Calendar cal, List<Date> dates) {
 57         calStartDate = cal;
 58         this.mContext = context;
 59         titles = getDates();
 60         this.markDates = dates;
 61     }
 62
 63     public CalendarGridViewAdapter(Context context) {
 64         this.mContext = context;
 65     }
 66
 67     @Override
 68     public int getCount() {
 69         return titles.size();
 70     }
 71
 72     @Override
 73     public Object getItem(int position) {
 74         return titles.get(position);
 75     }
 76
 77     @Override
 78     public long getItemId(int position) {
 79         return position;
 80     }
 81
 82     @SuppressWarnings("deprecation")
 83     @Override
 84     public View getView(int position, View convertView, ViewGroup parent) {
 85         // 整个Item
 86         LinearLayout itemLayout = new LinearLayout(mContext);
 87         itemLayout.setId(position + DEFAULT_ID);
 88         itemLayout.setGravity(Gravity.CENTER);
 89         itemLayout.setOrientation(1);
 90         itemLayout.setBackgroundColor(Color.WHITE);
 91
 92         Date myDate = (Date) getItem(position);
 93         itemLayout.setTag(myDate);
 94         Calendar calCalendar = Calendar.getInstance();
 95         calCalendar.setTime(myDate);
 96
 97         // 显示日期day
 98         TextView textDay = new TextView(mContext);// 日期
 99         LinearLayout.LayoutParams text_params = new LinearLayout.LayoutParams(
100                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
101         textDay.setGravity(Gravity.CENTER_HORIZONTAL);
102         int day = myDate.getDate(); // 日期
103         textDay.setTextSize(15);
104         textDay.setText(String.valueOf(day));
105         textDay.setId(position + DEFAULT_ID);
106         itemLayout.addView(textDay, text_params);
107
108         // 显示农历
109         TextView chineseDay = new TextView(mContext);
110         LinearLayout.LayoutParams chinese_params = new LinearLayout.LayoutParams(
111                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
112         chineseDay.setGravity(Gravity.CENTER_HORIZONTAL);
113         chineseDay.setTextSize(12);
114         CalendarUtil calendarUtil = new CalendarUtil(calCalendar);
115         chineseDay.setText(calendarUtil.toString());
116         itemLayout.addView(chineseDay, chinese_params);//把农历添加在公历下面
117
118         SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
119         Log.e("flag",equalsDate(calToday.getTime(),myDate)+sdf.format(calToday.getTime()));
120         // 如果是当前日期则显示不同颜色
121         if (equalsDate(calToday.getTime(), myDate)) {//假定当前是8月10日
122             itemLayout.setBackgroundColor(mContext.getResources().getColor(R.color.date_today_text_color));
123         }
124
125 //        Log.e("tag",equalsDate(myDate,calToday.getTime())+sdf.format(myDate));
126
127         Log.e("tag",myDate.getMonth()+"---"+sdf.format(myDate));
128         Log.e("tag",calToday.getTime().getMonth()+"====="+sdf.format(calToday.getTime()));
129         if (equalsMonth(myDate,calStartDate.getTime())){
130             textDay.setTextColor(mContext.getResources().getColor(R.color.date_text_color));
131             chineseDay.setTextColor(mContext.getResources().getColor(R.color.date_text_color));
132         }else{
133             textDay.setTextColor(mContext.getResources().getColor(R.color.date_pre_color));
134             chineseDay.setTextColor(mContext.getResources().getColor(R.color.date_pre_color));
135         }
136
137
138
139
140
141
164         /** 设置标注日期颜色 */
165         if (markDates != null) {
166             final SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日", Locale.CHINA);
167             for (Date date : markDates) {
168                 if (format.format(myDate).equals(format.format(date))) {
169 //                    itemLayout.setBackgroundColor(mContext.getResources().getColor(R.color.date_select_color));
170                     break;
171                 }
172             }
173         }
174         return itemLayout;
175     }
176
177     @Override
178     public void notifyDataSetChanged() {
179         super.notifyDataSetChanged();
180     }
181
182     @SuppressWarnings("deprecation")
183     private Boolean equalsDate(Date date1, Date date2) {
184         if (date1.getYear() == date2.getYear()
185                 && date1.getMonth() == date2.getMonth()
186                 && date1.getDate() == date2.getDate()) {
187             return true;
188         } else {
189             return false;
190         }
191     }
192     @SuppressWarnings("deprecation")
193     private boolean equalsMonth(Date date1,Date date2){
194         if (date1.getMonth() == date2.getMonth()-1){
195             return true;
196         }
197         return false;
198     }
199
200     // 根据改变的日期更新日历
201     // 填充日历控件用
202     private void UpdateStartDateForMonth() {
203         calStartDate.set(Calendar.DATE, 1); // 设置成当月第一天
204
205         // 星期一是2 星期天是1 填充剩余天数
206         int iDay = 0;
207         int iFirstDayOfWeek = Calendar.MONDAY;
208         int iStartDay = iFirstDayOfWeek;
209         if (iStartDay == Calendar.MONDAY) {
210             iDay = calStartDate.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY;
211             if (iDay < 0)
212                 iDay = 6;
213         }
214         if (iStartDay == Calendar.SUNDAY) {
215             iDay = calStartDate.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY;
216             if (iDay < 0)
217                 iDay = 6;
218         }
219         calStartDate.add(Calendar.DAY_OF_WEEK, -iDay);
220         calStartDate.add(Calendar.DAY_OF_MONTH, -1);// 周日第一位
221     }
222
223     public void setSelectedDate(Calendar cal) {
224         calSelected = cal;
225     }
226
227 }

3)

CalendarUtil
  1 package com.example.nanchen.mydateviewdemo.view;
  2
  3 import java.text.ParseException;
  4 import java.text.SimpleDateFormat;
  5 import java.util.Calendar;
  6 import java.util.Date;
  7
  8 /**
  9  * @author nanchen
 10  * @date 16-8-10 上午11:36
 11  */
 12 public class CalendarUtil {
 13     /**
 14      * 用于保存中文的月份
 15      */
 16     private final static String CHINESE_NUMBER[] = { "一", "二", "三", "四", "五",
 17             "六", "七", "八", "九", "十", "十一", "腊" };
 18
 19     /**
 20      * 用于保存展示周几使用
 21      */
 22     private final static String WEEK_NUMBER[] = { "日", "一", "二", "三", "四", "五",
 23             "六" };
 24
 25     private final static long[] LUNAR_INFO = new long[] { 0x04bd8, 0x04ae0,
 26             0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0,
 27             0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540,
 28             0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5,
 29             0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,
 30             0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3,
 31             0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0,
 32             0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0,
 33             0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8,
 34             0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570,
 35             0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5,
 36             0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0,
 37             0x195a6, 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50,
 38             0x06d40, 0x0af46, 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0,
 39             0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,
 40             0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7,
 41             0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50,
 42             0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954,
 43             0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260,
 44             0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0,
 45             0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0,
 46             0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20,
 47             0x0ada0 };
 48
 49     /**
 50      * 转换为2012年11月22日格式
 51      */
 52     private static SimpleDateFormat chineseDateFormat = new SimpleDateFormat(
 53             "yyyy年MM月dd日");
 54     /**
 55      * 转换为2012-11-22格式
 56      */
 57     private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
 58             "yyyy-MM-dd");
 59
 60     /**
 61      * 计算得到农历的年份
 62      */
 63     private int mLuchYear;
 64     /**
 65      * 计算得到农历的月份
 66      */
 67     private int mLuchMonth;
 68
 69     /**
 70      * 计算得到农历的日期
 71      */
 72     private int mLuchDay;
 73
 74     /**
 75      * 用于标识是事为闰年
 76      */
 77     private boolean isLoap;
 78
 79     /**
 80      * 用于记录当前处理的时间
 81      */
 82     private Calendar mCurrenCalendar;
 83
 84     /**
 85      * 传回农历 year年的总天数
 86      *
 87      * @param year
 88      *            将要计算的年份
 89      * @return 返回传入年份的总天数
 90      */
 91     private static int yearDays(int year) {
 92         int i, sum = 348;
 93         for (i = 0x8000; i > 0x8; i >>= 1) {
 94             if ((LUNAR_INFO[year - 1900] & i) != 0)
 95                 sum += 1;
 96         }
 97         return (sum + leapDays(year));
 98     }
 99
100     /**
101      * 传回农历 year年闰月的天数
102      *
103      * @param year
104      *            将要计算的年份
105      * @return 返回 农历 year年闰月的天数
106      */
107     private static int leapDays(int year) {
108         if (leapMonth(year) != 0) {
109             if ((LUNAR_INFO[year - 1900] & 0x10000) != 0)
110                 return 30;
111             else
112                 return 29;
113         } else
114             return 0;
115     }
116
117     /**
118      * 传回农历 year年闰哪个月 1-12 , 没闰传回 0
119      *
120      * @param year
121      *            将要计算的年份
122      * @return 传回农历 year年闰哪个月 1-12 , 没闰传回 0
123      */
124     private static int leapMonth(int year) {
125         return (int) (LUNAR_INFO[year - 1900] & 0xf);
126     }
127
128     /**
129      * 传回农历 year年month月的总天数
130      *
131      * @param year
132      *            将要计算的年份
133      * @param month
134      *            将要计算的月份
135      * @return 传回农历 year年month月的总天数
136      */
137     private static int monthDays(int year, int month) {
138         if ((LUNAR_INFO[year - 1900] & (0x10000 >> month)) == 0)
139             return 29;
140         else
141             return 30;
142     }
143
144     /**
145      * 传回农历 y年的生肖
146      *
147      * @return 传回农历 y年的生肖
148      */
149     public String animalsYear() {
150         final String[] Animals = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇",
151                 "马", "羊", "猴", "鸡", "狗", "猪" };
152         return Animals[(mLuchYear - 4) % 12];
153     }
154
155     // ====== 传入 月日的offset 传回干支, 0=甲子
156     private static String cyclicalm(int num) {
157         final String[] Gan = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚",
158                 "辛", "壬", "癸" };
159         final String[] Zhi = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午",
160                 "未", "申", "酉", "戌", "亥" };
161
162         return (Gan[num % 10] + Zhi[num % 12]);
163     }
164
165     // ====== 传入 offset 传回干支, 0=甲子
166     public String cyclical() {
167         int num = mLuchYear - 1900 + 36;
168         return (cyclicalm(num));
169     }
170
171     /**
172      * 传出y年m月d日对应的农历. yearCyl3:农历年与1864的相差数 ? monCyl4:从1900年1月31日以来,闰月数
173      * dayCyl5:与1900年1月31日相差的天数,再加40 ?
174      *
175      * @param cal
176      * @return
177      */
178     public CalendarUtil(Calendar cal) {
179         mCurrenCalendar = cal;
180         int leapMonth = 0;
181         Date baseDate = null;
182         try {
183             baseDate = chineseDateFormat.parse("1900年1月31日");
184         } catch (ParseException e) {
185             e.printStackTrace(); // To change body of catch statement use
186             // Options | File Templates.
187         }
188
189         // 求出和1900年1月31日相差的天数
190         int offset = (int) ((cal.getTime().getTime() - baseDate.getTime()) / 86400000L);
191         // 用offset减去每农历年的天数
192         // 计算当天是农历第几天
193         // i最终结果是农历的年份
194         // offset是当年的第几天
195         int iYear, daysOfYear = 0;
196         for (iYear = 1900; iYear < 2050 && offset > 0; iYear++) {
197             daysOfYear = yearDays(iYear);
198             offset -= daysOfYear;
199         }
200         if (offset < 0) {
201             offset += daysOfYear;
202             iYear--;
203         }
204         // 农历年份
205         mLuchYear = iYear;
206
207         leapMonth = leapMonth(iYear); // 闰哪个月,1-12
208         isLoap = false;
209
210         // 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天
211         int iMonth, daysOfMonth = 0;
212         for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) {
213             // 闰月
214             if (leapMonth > 0 && iMonth == (leapMonth + 1) && !isLoap) {
215                 --iMonth;
216                 isLoap = true;
217                 daysOfMonth = leapDays(mLuchYear);
218             } else
219                 daysOfMonth = monthDays(mLuchYear, iMonth);
220
221             offset -= daysOfMonth;
222             // 解除闰月
223             if (isLoap && iMonth == (leapMonth + 1))
224                 isLoap = false;
225             if (!isLoap) {
226             }
227         }
228         // offset为0时,并且刚才计算的月份是闰月,要校正
229         if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) {
230             if (isLoap) {
231                 isLoap = false;
232             } else {
233                 isLoap = true;
234                 --iMonth;
235             }
236         }
237         // offset小于0时,也要校正
238         if (offset < 0) {
239             offset += daysOfMonth;
240             --iMonth;
241
242         }
243         mLuchMonth = iMonth;
244         mLuchDay = offset + 1;
245     }
246
247     /**
248      * 返化成中文格式
249      *
250      * @param day
251      * @return
252      */
253     public static String getChinaDayString(int day) {
254         String chineseTen[] = { "初", "十", "廿", "卅" };
255         int n = day % 10 == 0 ? 9 : day % 10 - 1;
256         if (day > 30)
257             return "";
258         if (day == 10)
259             return "初十";
260         else
261             return chineseTen[day / 10] + CHINESE_NUMBER[n];
262     }
263
264     /**
265      * 用于显示农历的初几这种格式
266      *
267      * @return 农历的日期
268      */
269     public String toString() {
270         String message = "";
271         // int n = mLuchDay % 10 == 0 ? 9 : mLuchDay % 10 - 1;
272         message = getChinaCalendarMsg(mLuchYear, mLuchMonth, mLuchDay);
273         if (StringUtil.isNullOrEmpty(message)) {
274             String solarMsg = new SolarTermsUtil(mCurrenCalendar)
275                     .getSolartermsMsg();
276             // 判断当前日期是否为节气
277             if (!StringUtil.isNullOrEmpty(solarMsg)) {
278                 message = solarMsg;
279             } else {
280                 /**
281                  * 判断当前日期是否为公历节日
282                  */
283                 String gremessage = new GregorianUtil(mCurrenCalendar)
284                         .getGremessage();
285                 if (!StringUtil.isNullOrEmpty(gremessage)) {
286                     message = gremessage;
287                 } else if (mLuchDay == 1) {
288                     message = CHINESE_NUMBER[mLuchMonth - 1] + "月";
289                 } else {
290                     message = getChinaDayString(mLuchDay);
291                 }
292
293             }
294         }
295         return message;
296     }
297
298     /**
299      * 返回农历的年月日
300      *
301      * @return 农历的年月日格式
302      */
303     public String getDay() {
304         return (isLoap ? "闰" : "") + CHINESE_NUMBER[mLuchMonth - 1] + "月"
305                 + getChinaDayString(mLuchDay);
306     }
307
308     /**
309      * 把calendar转化为当前年月日
310      *
311      * @param calendar
312      *            Calendar
313      * @return 返回成转换好的 年月日格式
314      */
315     public static String getDay(Calendar calendar) {
316         return simpleDateFormat.format(calendar.getTime());
317     }
318
319     /**
320      * 用于比对二个日期的大小
321      *
322      * @param compareDate
323      *            将要比对的时间
324      * @param currentDate
325      *            当前时间
326      * @return true 表示大于当前时间 false 表示小于当前时间
327      */
328     public static boolean compare(Date compareDate, Date currentDate) {
329         return chineseDateFormat.format(compareDate).compareTo(
330                 chineseDateFormat.format(currentDate)) >= 0;
331     }
332
333     /**
334      * 获取当前周几
335      *
336      * @param calendar
337      * @return
338      */
339     public static String getWeek(Calendar calendar) {
340         return "周" + WEEK_NUMBER[calendar.get(Calendar.DAY_OF_WEEK) - 1] + "";
341     }
342
343     /**
344      * 将当前时间转换成要展示的形式
345      *
346      * @param calendar
347      * @return
348      */
349     public static String getCurrentDay(Calendar calendar) {
350         return getDay(calendar) + " 农历" + new CalendarUtil(calendar).getDay()
351                 + " " + getWeek(calendar);
352     }
353
354     /**
355      * 用于获取中国的传统节日
356      *
357      * @param month
358      *            农历的月
359      * @param day
360      *            农历日
361      * @return 中国传统节日
362      */
363     private String getChinaCalendarMsg(int year, int month, int day) {
364         String message = "";
365         if (((month) == 1) && day == 1) {
366             message = "春节";
367         } else if (((month) == 1) && day == 15) {
368             message = "元宵";
369         } else if (((month) == 5) && day == 5) {
370             message = "端午";
371         } else if ((month == 7) && day == 7) {
372             message = "七夕";
373         } else if (((month) == 8) && day == 15) {
374             message = "中秋";
375         } else if ((month == 9) && day == 9) {
376             message = "重阳";
377         } else if ((month == 12) && day == 8) {
378             message = "腊八";
379         } else {
380             if (month == 12) {
381                 if ((((monthDays(year, month) == 29) && day == 29))
382                         || ((((monthDays(year, month) == 30) && day == 30)))) {
383                     message = "除夕";
384                 }
385             }
386         }
387         return message;
388     }
389 }

4)

CalendarView
  1 package com.example.nanchen.mydateviewdemo.view;
  2
  3 import android.annotation.SuppressLint;
  4 import android.content.Context;
  5 import android.graphics.Color;
  6 import android.text.TextUtils.TruncateAt;
  7 import android.util.AttributeSet;
  8 import android.view.GestureDetector;
  9 import android.view.GestureDetector.OnGestureListener;
 10 import android.view.Gravity;
 11 import android.view.MotionEvent;
 12 import android.view.View;
 13 import android.view.View.OnTouchListener;
 14 import android.view.animation.Animation;
 15 import android.view.animation.Animation.AnimationListener;
 16 import android.view.animation.TranslateAnimation;
 17 import android.widget.GridView;
 18 import android.widget.ImageButton;
 19 import android.widget.LinearLayout;
 20 import android.widget.RelativeLayout;
 21 import android.widget.TextView;
 22 import android.widget.ViewFlipper;
 23
 24 import com.example.nanchen.mydateviewdemo.R;
 25
 26 import java.util.ArrayList;
 27 import java.util.Calendar;
 28 import java.util.Date;
 29 import java.util.List;
 30
 31 /**
 32  * @author nanchen
 33  * @date 16-8-10 上午11:40
 34  */
 35 public class CalendarView extends LinearLayout implements OnTouchListener, AnimationListener, OnGestureListener {
 36
 37     /**
 38      * 点击日历
 39      */
 40     public interface OnCalendarViewListener {
 41         void onCalendarItemClick(CalendarView view, Date date);
 42     }
 43
 44     /**
 45      * 顶部控件所占高度
 46      */
 47     private final static int TOP_HEIGHT = 40;
 48     /**
 49      * 日历item中默认id从0xff0000开始
 50      */
 51     private final static int DEFAULT_ID = 0xff0000;
 52
 53     // 判断手势用
 54     private static final int SWIPE_MIN_DISTANCE = 120;
 55     private static final int SWIPE_MAX_OFF_PATH = 250;
 56     private static final int SWIPE_THRESHOLD_VELOCITY = 200;
 57
 58     // 屏幕宽度和高度
 59     private int screenWidth;
 60
 61     // 动画
 62     private Animation slideLeftIn;
 63     private Animation slideLeftOut;
 64     private Animation slideRightIn;
 65     private Animation slideRightOut;
 66     private ViewFlipper viewFlipper;
 67     private GestureDetector mGesture = null;
 68
 69     /**
 70      * 上一月
 71      */
 72     private GridView gView1;
 73     /**
 74      * 当月
 75      */
 76     private GridView gView2;
 77     /**
 78      * 下一月
 79      */
 80     private GridView gView3;
 81
 82     boolean bIsSelection = false;// 是否是选择事件发生
 83     private Calendar calStartDate = Calendar.getInstance();// 当前显示的日历
 84     private Calendar calSelected = Calendar.getInstance(); // 选择的日历
 85     private CalendarGridViewAdapter gAdapter;
 86     private CalendarGridViewAdapter gAdapter1;
 87     private CalendarGridViewAdapter gAdapter3;
 88
 89     private LinearLayout mMainLayout;
 90     private TextView mTitle; // 显示年月
 91
 92     private int iMonthViewCurrentMonth = 0; // 当前视图月
 93     private int iMonthViewCurrentYear = 0; // 当前视图年
 94
 95     private static final int caltitleLayoutID = 66; // title布局ID
 96     private static final int calLayoutID = 55; // 日历布局ID
 97     private Context mContext;
 98
 99     /**
100      * 标注日期
101      */
102     private final List<Date> markDates;
103
104     private OnCalendarViewListener mListener;
105
106     public CalendarView(Context context) {
107         this(context, null);
108     }
109
110     public CalendarView(Context context, AttributeSet attrs) {
111         super(context, attrs);
112         // TODO Auto-generated constructor stub
113         mContext = context;
114         markDates = new ArrayList<>();
115         init();
116     }
117
118     // 初始化相关工作
119     protected void init() {
120         // 得到屏幕的宽度
121         screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
122
123         // 滑动的动画
124         slideLeftIn = new TranslateAnimation(screenWidth, 0, 0, 0);
125         slideLeftIn.setDuration(400);
126         slideLeftIn.setAnimationListener(this);
127         slideLeftOut = new TranslateAnimation(0, -screenWidth, 0, 0);
128         slideLeftOut.setDuration(400);
129         slideLeftOut.setAnimationListener(this);
130         slideRightIn = new TranslateAnimation(-screenWidth, 0, 0, 0);
131         slideRightIn.setDuration(400);
132         slideRightIn.setAnimationListener(this);
133         slideRightOut = new TranslateAnimation(0, screenWidth, 0, 0);
134         slideRightOut.setDuration(400);
135         slideRightOut.setAnimationListener(this);
136
137         // 手势操作
138         mGesture = new GestureDetector(mContext, this);
139
140         // 获取到当前日期
141         UpdateStartDateForMonth();
142         // 绘制界面
143         setOrientation(LinearLayout.HORIZONTAL);
144         mMainLayout = new LinearLayout(mContext);
145         LinearLayout.LayoutParams main_params = new LinearLayout.LayoutParams(
146                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
147         mMainLayout.setLayoutParams(main_params);
148         mMainLayout.setGravity(Gravity.CENTER_HORIZONTAL);
149         mMainLayout.setOrientation(LinearLayout.VERTICAL);
150         addView(mMainLayout);
151
152         // 顶部控件
153         generateTopView();
154
155         // 中间显示星期
156         generateWeekGirdView();
157
158         // 底部显示日历
159         viewFlipper = new ViewFlipper(mContext);
160         RelativeLayout.LayoutParams fliper_params = new RelativeLayout.LayoutParams(
161                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
162         fliper_params.addRule(RelativeLayout.BELOW, caltitleLayoutID);
163         mMainLayout.addView(viewFlipper, fliper_params);
164         generateClaendarGirdView();
165
166         // 最下方的一条线条
167         LinearLayout br = new LinearLayout(mContext);
168         br.setBackgroundColor(Color.argb(0xff, 0xe3, 0xee, 0xf4));
169         LinearLayout.LayoutParams params_br = new LinearLayout.LayoutParams(
170                 LayoutParams.MATCH_PARENT, 3);
171         mMainLayout.addView(br, params_br);
172     }
173
174     /**
175      * 生成顶部控件
176      */
177     @SuppressWarnings("deprecation")
178     private void generateTopView() {
179         // 顶部显示上一个下一个,以及当前年月
180         RelativeLayout top = new RelativeLayout(mContext);
181         top.setBackgroundColor(Color.argb(0xff, 0x0e, 0x6b, 0xc2));
182         LinearLayout.LayoutParams top_params = new LinearLayout.LayoutParams(
183                 LayoutParams.MATCH_PARENT,
184                 ViewUtil.dip2px(mContext, TOP_HEIGHT));
185         top.setLayoutParams(top_params);
186         mMainLayout.addView(top);
187         // 左方按钮、中间日期显示、右方按钮
188         mTitle = new TextView(mContext);
189         android.widget.RelativeLayout.LayoutParams title_params = new android.widget.RelativeLayout.LayoutParams(
190                 android.widget.RelativeLayout.LayoutParams.MATCH_PARENT,
191                 android.widget.RelativeLayout.LayoutParams.MATCH_PARENT);
192         mTitle.setLayoutParams(title_params);
193         mTitle.setTextColor(Color.WHITE);
194         mTitle.setTextSize(18);
195         mTitle.setFocusableInTouchMode(true);
196         mTitle.setMarqueeRepeatLimit(-1);
197         mTitle.setEllipsize(TruncateAt.MARQUEE);
198         mTitle.setSingleLine(true);
199         mTitle.setGravity(Gravity.CENTER);
200         mTitle.setHorizontallyScrolling(true);
201         mTitle.setText("2014年9月");
202         top.addView(mTitle);
203
204         // 左方按钮
205         ImageButton mLeftView = new ImageButton(mContext);
206
218
219         mLeftView.setBackgroundResource(R.drawable.month_pre_selector);
220         android.widget.RelativeLayout.LayoutParams leftPP = new android.widget.RelativeLayout.LayoutParams(
221                 ViewUtil.dip2px(mContext, 25), ViewUtil.dip2px(mContext, 22));
222         leftPP.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
223         leftPP.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
224         leftPP.setMargins(20, 0, 0, 0);
225         mLeftView.setLayoutParams(leftPP);
226         mLeftView.setOnClickListener(new OnClickListener() {
227
228             @Override
229             public void onClick(View v) {
230                 // TODO Auto-generated method stub
231                 viewFlipper.setInAnimation(slideRightIn);
232                 viewFlipper.setOutAnimation(slideRightOut);
233                 viewFlipper.showPrevious();
234                 setPrevViewItem();
235             }
236         });
237         top.addView(mLeftView);
238
239         // 右方按钮
240         ImageButton mRightView = new ImageButton(mContext);
241
253
254         mRightView.setBackgroundResource(R.drawable.month_next_selector);
255
256         android.widget.RelativeLayout.LayoutParams rightPP = new android.widget.RelativeLayout.LayoutParams(
257                 ViewUtil.dip2px(mContext, 25), ViewUtil.dip2px(mContext, 22));
258         rightPP.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
259         rightPP.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
260         rightPP.setMargins(0, 0, 20, 0);
261         mRightView.setLayoutParams(rightPP);
262         mRightView.setOnClickListener(new OnClickListener() {
263
264             @Override
265             public void onClick(View v) {
266                 // TODO Auto-generated method stub
267                 viewFlipper.setInAnimation(slideLeftIn);
268                 viewFlipper.setOutAnimation(slideLeftOut);
269                 viewFlipper.showNext();
270                 setNextViewItem();
271             }
272         });
273         top.addView(mRightView);
274     }
275
276     /**
277      * 生成中间显示week
278      */
279     private void generateWeekGirdView() {
280         GridView gridView = new GridView(mContext);
281         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
282                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
283         gridView.setLayoutParams(params);
284         gridView.setNumColumns(7);// 设置每行列数
285         gridView.setGravity(Gravity.CENTER_VERTICAL);// 位置居中
286         gridView.setVerticalSpacing(1);// 垂直间隔
287         gridView.setHorizontalSpacing(1);// 水平间隔
288         gridView.setBackgroundColor(Color.argb(0xff, 0xe3, 0xee, 0xf4));
289
290         int i = screenWidth / 7;
291         int j = screenWidth - (i * 7);
292         int x = j / 2;
293         gridView.setPadding(x, 0, 0, 0);// 居中
294         WeekGridAdapter weekAdapter = new WeekGridAdapter(mContext);
295         gridView.setAdapter(weekAdapter);// 设置菜单Adapter
296         mMainLayout.addView(gridView);
297     }
298
299     /**
300      * 生成底部日历
301      */
302     private void generateClaendarGirdView() {
303         Calendar tempSelected1 = Calendar.getInstance(); // 临时
304         Calendar tempSelected2 = Calendar.getInstance(); // 临时
305         Calendar tempSelected3 = Calendar.getInstance(); // 临时
306         tempSelected1.setTime(calStartDate.getTime());
307         tempSelected2.setTime(calStartDate.getTime());
308         tempSelected3.setTime(calStartDate.getTime());
309
310         gView1 = new CalendarGridView(mContext);
311         tempSelected1.add(Calendar.MONTH, -1);
312         gAdapter1 = new CalendarGridViewAdapter(mContext, tempSelected1,
313                 markDates);
314         gView1.setAdapter(gAdapter1);// 设置菜单Adapter
315         gView1.setId(calLayoutID);
316
317         gView2 = new CalendarGridView(mContext);
318         gAdapter = new CalendarGridViewAdapter(mContext, tempSelected2,
319                 markDates);
320         gView2.setAdapter(gAdapter);// 设置菜单Adapter
321         gView2.setId(calLayoutID);
322
323         gView3 = new CalendarGridView(mContext);
324         tempSelected3.add(Calendar.MONTH, 1);
325         gAdapter3 = new CalendarGridViewAdapter(mContext, tempSelected3,
326                 markDates);
327         gView3.setAdapter(gAdapter3);// 设置菜单Adapter
328         gView3.setId(calLayoutID);
329
330         gView2.setOnTouchListener(this);
331         gView1.setOnTouchListener(this);
332         gView3.setOnTouchListener(this);
333
334         if (viewFlipper.getChildCount() != 0) {
335             viewFlipper.removeAllViews();
336         }
337
338         viewFlipper.addView(gView2);
339         viewFlipper.addView(gView3);
340         viewFlipper.addView(gView1);
341
342         String title = calStartDate.get(Calendar.YEAR)
343                 + "年"
344                 + NumberHelper.LeftPad_Tow_Zero(calStartDate
345                 .get(Calendar.MONTH) + 1) + "月";
346         mTitle.setText(title);
347     }
348
349     // 上一个月
350     private void setPrevViewItem() {
351         iMonthViewCurrentMonth--;// 当前选择月--
352         // 如果当前月为负数的话显示上一年
353         if (iMonthViewCurrentMonth == -1) {
354             iMonthViewCurrentMonth = 11;
355             iMonthViewCurrentYear--;
356         }
357         calStartDate.set(Calendar.DAY_OF_MONTH, 1); // 设置日为当月1日
358         calStartDate.set(Calendar.MONTH, iMonthViewCurrentMonth); // 设置月
359         calStartDate.set(Calendar.YEAR, iMonthViewCurrentYear); // 设置年
360     }
361
362     // 下一个月
363     private void setNextViewItem() {
364         iMonthViewCurrentMonth++;
365         if (iMonthViewCurrentMonth == 12) {
366             iMonthViewCurrentMonth = 0;
367             iMonthViewCurrentYear++;
368         }
369         calStartDate.set(Calendar.DAY_OF_MONTH, 1);
370         calStartDate.set(Calendar.MONTH, iMonthViewCurrentMonth);
371         calStartDate.set(Calendar.YEAR, iMonthViewCurrentYear);
372     }
373
374     // 根据改变的日期更新日历
375     // 填充日历控件用
376     private void UpdateStartDateForMonth() {
377         calStartDate.set(Calendar.DATE, 1); // 设置成当月第一天
378         iMonthViewCurrentMonth = calStartDate.get(Calendar.MONTH);// 得到当前日历显示的月
379         iMonthViewCurrentYear = calStartDate.get(Calendar.YEAR);// 得到当前日历显示的年
380
381         // 星期一是2 星期天是1 填充剩余天数
382         int iDay = 0;
383         int iFirstDayOfWeek = Calendar.MONDAY;
384         int iStartDay = iFirstDayOfWeek;
385         if (iStartDay == Calendar.MONDAY) {
386             iDay = calStartDate.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY;
387             if (iDay < 0)
388                 iDay = 6;
389         }
390         if (iStartDay == Calendar.SUNDAY) {
391             iDay = calStartDate.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY;
392             if (iDay < 0)
393                 iDay = 6;
394         }
395         calStartDate.add(Calendar.DAY_OF_WEEK, -iDay);
396     }
397
398     /**
399      * 设置标注的日期
400      *
401      * @param markDates
402      */
403     public void setMarkDates(List<Date> markDates) {
404         this.markDates.clear();
405         this.markDates.addAll(markDates);
406         gAdapter.notifyDataSetChanged();
407         gAdapter1.notifyDataSetChanged();
408         gAdapter3.notifyDataSetChanged();
409     }
410
411     /**
412      * 设置点击日历监听
413      *
414      * @param listener
415      */
416     public void setOnCalendarViewListener(OnCalendarViewListener listener) {
417         this.mListener = listener;
418     }
419
420     @Override
421     public boolean onDown(MotionEvent e) {
422         // TODO Auto-generated method stub
423         return false;
424     }
425
426     @SuppressLint("ClickableViewAccessibility")
427     @Override
428     public boolean onTouch(View v, MotionEvent event) {
429         return mGesture.onTouchEvent(event);
430     }
431
432     @Override
433     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
434                            float velocityY) {
435         // TODO Auto-generated method stub
436         try {
437             if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
438                 return false;
439             // right to left swipe
440             if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
441                     && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
442                 viewFlipper.setInAnimation(slideLeftIn);
443                 viewFlipper.setOutAnimation(slideLeftOut);
444                 viewFlipper.showNext();
445                 setNextViewItem();
446                 return true;
447
448             } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
449                     && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
450                 viewFlipper.setInAnimation(slideRightIn);
451                 viewFlipper.setOutAnimation(slideRightOut);
452                 viewFlipper.showPrevious();
453                 setPrevViewItem();
454                 return true;
455
456             }
457         } catch (Exception e) {
458             // nothing
459         }
460         return false;
461     }
462
463     @Override
464     public void onLongPress(MotionEvent e) {
465         // TODO Auto-generated method stub
466
467     }
468
469     @Override
470     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
471                             float distanceY) {
472         // TODO Auto-generated method stub
473         return false;
474     }
475
476     @Override
477     public void onShowPress(MotionEvent e) {
478         // TODO Auto-generated method stub
479
480     }
481
482     @Override
483     public boolean onSingleTapUp(MotionEvent e) {
484         // TODO Auto-generated method stub
485         // 得到当前选中的是第几个单元格
486         int pos = gView2.pointToPosition((int) e.getX(), (int) e.getY());
487         LinearLayout txtDay = (LinearLayout) gView2.findViewById(pos
488                 + DEFAULT_ID);
489         if (txtDay != null) {
490             if (txtDay.getTag() != null) {
491                 Date date = (Date) txtDay.getTag();
492                 calSelected.setTime(date);
493
494                 gAdapter.setSelectedDate(calSelected);
495                 gAdapter.notifyDataSetChanged();
496
497                 gAdapter1.setSelectedDate(calSelected);
498                 gAdapter1.notifyDataSetChanged();
499
500                 gAdapter3.setSelectedDate(calSelected);
501                 gAdapter3.notifyDataSetChanged();
502                 if (mListener != null)
503                     mListener.onCalendarItemClick(this, date);
504             }
505         }
506         return false;
507     }
508
509     @Override
510     public void onAnimationEnd(Animation animation) {
511         // TODO Auto-generated method stub
512         generateClaendarGirdView();
513     }
514
515     @Override
516     public void onAnimationRepeat(Animation animation) {
517         // TODO Auto-generated method stub
518
519     }
520
521     @Override
522     public void onAnimationStart(Animation animation) {
523         // TODO Auto-generated method stub
524
525     }
526 }

5)

GregorianUtil
 1 package com.example.nanchen.mydateviewdemo.view;
 2
 3 import java.util.Calendar;
 4
 5 /**
 6  * 对公历日期的处理类
 7  * @author nanchen
 8  * @date 16-8-10 上午11:37
 9  */
10 public class GregorianUtil {
11     private final static String[][] GRE_FESTVIAL = {
12             // 一月
13             { "元旦", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
14                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
15             // 二月
16             { "", "", "", "", "", "", "", "", "", "", "", "", "", "情人", "", "",
17                     "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
18             // 三月
19             { "", "", "", "", "", "", "", "妇女", "", "", "", "植树", "", "", "",
20                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
21                     "" },
22             // 四月
23             { "愚人", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
24                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
25             // 五月
26             { "劳动", "", "", "青年", "", "", "", "", "", "", "", "", "", "", "",
27                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
28                     "" },
29             // 六月
30             { "儿童", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
31                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
32             // 七月
33             { "建党", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
34                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
35             // 八月
36             { "建军", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
37                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
38             // 九月
39             { "", "", "", "", "", "", "", "", "", "教师", "", "", "", "", "", "",
40                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
41             // 十月
42             { "国庆", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
43                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
44             // 十一月
45             { "", "", "", "", "", "", "", "", "", "", "光棍", "", "", "", "", "",
46                     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
47             // 十二月
48             { "艾滋病", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
49                     "", "", "", "", "", "", "", "", "", "圣诞", "", "", "", "",
50                     "", "" }, };
51     private int mMonth;
52     private int mDay;
53
54     public GregorianUtil(Calendar calendar) {
55         mMonth = calendar.get(Calendar.MONTH);
56         mDay = calendar.get(Calendar.DATE);
57     }
58
59     public String getGremessage() {
60         return GRE_FESTVIAL[mMonth][mDay - 1];
61     }
62 }

6)

 1 package com.example.nanchen.mydateviewdemo.view;
 2
 3 /**
 4  * @author nanchen
 5  * @date 16-8-10 上午11:38
 6  */
 7 public class NumberHelper {
 8     public static String LeftPad_Tow_Zero(int str) {
 9         java.text.DecimalFormat format = new java.text.DecimalFormat("00");
10         return format.format(str);
11     }
12 }

7)

SolarTermsUtil
  1 package com.example.nanchen.mydateviewdemo.view;
  2
  3 import java.util.Calendar;
  4
  5 /**
  6  * 主要用于把公历日期处理成24节气
  7  * @author nanchen
  8  * @date 16-8-10 上午11:38
  9  */
 10 public class SolarTermsUtil {
 11     /**
 12      * 计算得到公历的年份
 13      */
 14     private int gregorianYear;
 15
 16     /**
 17      * 计算得到公历的月份
 18      */
 19     private int gregorianMonth;
 20
 21     /**
 22      * 用于计算得到公历的日期
 23      */
 24     private int gregorianDate;
 25
 26     private int chineseYear;
 27     private int chineseMonth;
 28     private int chineseDate;
 29
 30     // 初始日,公历农历对应日期:
 31     // 公历 1901 年 1 月 1 日,对应农历 4598 年 11 月 11 日
 32     private static int baseYear = 1901;
 33     private static int baseMonth = 1;
 34     private static int baseDate = 1;
 35     private static int baseIndex = 0;
 36     private static int baseChineseYear = 4598 - 1;
 37     private static int baseChineseMonth = 11;
 38     private static int baseChineseDate = 11;
 39     private static char[] daysInGregorianMonth = { 31, 28, 31, 30, 31, 30, 31,
 40             31, 30, 31, 30, 31 };
 41
 42     private int sectionalTerm;
 43     private int principleTerm;
 44
 45     private static char[][] sectionalTermMap = {
 46             { 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 5, 5,
 47                     5, 5, 5, 4, 5, 5 },
 48             { 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 3,
 49                     3, 4, 4, 3, 3, 3 },
 50             { 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
 51                     5, 5, 4, 5, 5, 5, 5 },
 52             { 5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4,
 53                     4, 5, 4, 4, 4, 4, 5 },
 54             { 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
 55                     5, 5, 4, 5, 5, 5, 5 },
 56             { 6, 6, 7, 7, 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5,
 57                     5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5 },
 58             { 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
 59                     7, 7, 6, 6, 6, 7, 7 },
 60             { 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
 61                     7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7 },
 62             { 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
 63                     7, 7, 6, 7, 7, 7, 7 },
 64             { 9, 9, 9, 9, 8, 9, 9, 9, 8, 8, 9, 9, 8, 8, 8, 9, 8, 8, 8, 8, 7, 8,
 65                     8, 8, 7, 7, 8, 8, 8 },
 66             { 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7,
 67                     7, 7, 6, 6, 7, 7, 7 },
 68             { 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
 69                     7, 7, 6, 6, 6, 7, 7 } };
 70     private static char[][] sectionalTermYear = {
 71             { 13, 49, 85, 117, 149, 185, 201, 250, 250 },
 72             { 13, 45, 81, 117, 149, 185, 201, 250, 250 },
 73             { 13, 48, 84, 112, 148, 184, 200, 201, 250 },
 74             { 13, 45, 76, 108, 140, 172, 200, 201, 250 },
 75             { 13, 44, 72, 104, 132, 168, 200, 201, 250 },
 76             { 5, 33, 68, 96, 124, 152, 188, 200, 201 },
 77             { 29, 57, 85, 120, 148, 176, 200, 201, 250 },
 78             { 13, 48, 76, 104, 132, 168, 196, 200, 201 },
 79             { 25, 60, 88, 120, 148, 184, 200, 201, 250 },
 80             { 16, 44, 76, 108, 144, 172, 200, 201, 250 },
 81             { 28, 60, 92, 124, 160, 192, 200, 201, 250 },
 82             { 17, 53, 85, 124, 156, 188, 200, 201, 250 } };
 83     private static char[][] principleTermMap = {
 84             { 21, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20,
 85                     20, 20, 20, 20, 20, 19, 20, 20, 20, 19, 19, 20 },
 86             { 20, 19, 19, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18, 19, 19,
 87                     19, 18, 18, 19, 19, 18, 18, 18, 18, 18, 18, 18 },
 88             { 21, 21, 21, 22, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21,
 89                     20, 20, 20, 21, 20, 20, 20, 20, 19, 20, 20, 20, 20 },
 90             { 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 20, 20, 20, 20,
 91                     19, 20, 20, 20, 19, 19, 20, 20, 19, 19, 19, 20, 20 },
 92             { 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21,
 93                     20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 21 },
 94             { 22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22,
 95                     21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 21 },
 96             { 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23,
 97                     22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 23 },
 98             { 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
 99                     22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 },
100             { 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
101                     22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 },
102             { 24, 24, 24, 24, 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24,
103                     23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 23 },
104             { 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23,
105                     22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 22 },
106             { 22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 21, 22, 22, 22,
107                     21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21, 22 } };
108     private static char[][] principleTermYear = {
109             { 13, 45, 81, 113, 149, 185, 201 },
110             { 21, 57, 93, 125, 161, 193, 201 },
111             { 21, 56, 88, 120, 152, 188, 200, 201 },
112             { 21, 49, 81, 116, 144, 176, 200, 201 },
113             { 17, 49, 77, 112, 140, 168, 200, 201 },
114             { 28, 60, 88, 116, 148, 180, 200, 201 },
115             { 25, 53, 84, 112, 144, 172, 200, 201 },
116             { 29, 57, 89, 120, 148, 180, 200, 201 },
117             { 17, 45, 73, 108, 140, 168, 200, 201 },
118             { 28, 60, 92, 124, 160, 192, 200, 201 },
119             { 16, 44, 80, 112, 148, 180, 200, 201 },
120             { 17, 53, 88, 120, 156, 188, 200, 201 } };
121
122     private static char[] chineseMonths = {
123             // 农历月份大小压缩表,两个字节表示一年。两个字节共十六个二进制位数,
124             // 前四个位数表示闰月月份,后十二个位数表示十二个农历月份的大小。
125             0x00, 0x04, 0xad, 0x08, 0x5a, 0x01, 0xd5, 0x54, 0xb4, 0x09, 0x64,
126             0x05, 0x59, 0x45, 0x95, 0x0a, 0xa6, 0x04, 0x55, 0x24, 0xad, 0x08,
127             0x5a, 0x62, 0xda, 0x04, 0xb4, 0x05, 0xb4, 0x55, 0x52, 0x0d, 0x94,
128             0x0a, 0x4a, 0x2a, 0x56, 0x02, 0x6d, 0x71, 0x6d, 0x01, 0xda, 0x02,
129             0xd2, 0x52, 0xa9, 0x05, 0x49, 0x0d, 0x2a, 0x45, 0x2b, 0x09, 0x56,
130             0x01, 0xb5, 0x20, 0x6d, 0x01, 0x59, 0x69, 0xd4, 0x0a, 0xa8, 0x05,
131             0xa9, 0x56, 0xa5, 0x04, 0x2b, 0x09, 0x9e, 0x38, 0xb6, 0x08, 0xec,
132             0x74, 0x6c, 0x05, 0xd4, 0x0a, 0xe4, 0x6a, 0x52, 0x05, 0x95, 0x0a,
133             0x5a, 0x42, 0x5b, 0x04, 0xb6, 0x04, 0xb4, 0x22, 0x6a, 0x05, 0x52,
134             0x75, 0xc9, 0x0a, 0x52, 0x05, 0x35, 0x55, 0x4d, 0x0a, 0x5a, 0x02,
135             0x5d, 0x31, 0xb5, 0x02, 0x6a, 0x8a, 0x68, 0x05, 0xa9, 0x0a, 0x8a,
136             0x6a, 0x2a, 0x05, 0x2d, 0x09, 0xaa, 0x48, 0x5a, 0x01, 0xb5, 0x09,
137             0xb0, 0x39, 0x64, 0x05, 0x25, 0x75, 0x95, 0x0a, 0x96, 0x04, 0x4d,
138             0x54, 0xad, 0x04, 0xda, 0x04, 0xd4, 0x44, 0xb4, 0x05, 0x54, 0x85,
139             0x52, 0x0d, 0x92, 0x0a, 0x56, 0x6a, 0x56, 0x02, 0x6d, 0x02, 0x6a,
140             0x41, 0xda, 0x02, 0xb2, 0xa1, 0xa9, 0x05, 0x49, 0x0d, 0x0a, 0x6d,
141             0x2a, 0x09, 0x56, 0x01, 0xad, 0x50, 0x6d, 0x01, 0xd9, 0x02, 0xd1,
142             0x3a, 0xa8, 0x05, 0x29, 0x85, 0xa5, 0x0c, 0x2a, 0x09, 0x96, 0x54,
143             0xb6, 0x08, 0x6c, 0x09, 0x64, 0x45, 0xd4, 0x0a, 0xa4, 0x05, 0x51,
144             0x25, 0x95, 0x0a, 0x2a, 0x72, 0x5b, 0x04, 0xb6, 0x04, 0xac, 0x52,
145             0x6a, 0x05, 0xd2, 0x0a, 0xa2, 0x4a, 0x4a, 0x05, 0x55, 0x94, 0x2d,
146             0x0a, 0x5a, 0x02, 0x75, 0x61, 0xb5, 0x02, 0x6a, 0x03, 0x61, 0x45,
147             0xa9, 0x0a, 0x4a, 0x05, 0x25, 0x25, 0x2d, 0x09, 0x9a, 0x68, 0xda,
148             0x08, 0xb4, 0x09, 0xa8, 0x59, 0x54, 0x03, 0xa5, 0x0a, 0x91, 0x3a,
149             0x96, 0x04, 0xad, 0xb0, 0xad, 0x04, 0xda, 0x04, 0xf4, 0x62, 0xb4,
150             0x05, 0x54, 0x0b, 0x44, 0x5d, 0x52, 0x0a, 0x95, 0x04, 0x55, 0x22,
151             0x6d, 0x02, 0x5a, 0x71, 0xda, 0x02, 0xaa, 0x05, 0xb2, 0x55, 0x49,
152             0x0b, 0x4a, 0x0a, 0x2d, 0x39, 0x36, 0x01, 0x6d, 0x80, 0x6d, 0x01,
153             0xd9, 0x02, 0xe9, 0x6a, 0xa8, 0x05, 0x29, 0x0b, 0x9a, 0x4c, 0xaa,
154             0x08, 0xb6, 0x08, 0xb4, 0x38, 0x6c, 0x09, 0x54, 0x75, 0xd4, 0x0a,
155             0xa4, 0x05, 0x45, 0x55, 0x95, 0x0a, 0x9a, 0x04, 0x55, 0x44, 0xb5,
156             0x04, 0x6a, 0x82, 0x6a, 0x05, 0xd2, 0x0a, 0x92, 0x6a, 0x4a, 0x05,
157             0x55, 0x0a, 0x2a, 0x4a, 0x5a, 0x02, 0xb5, 0x02, 0xb2, 0x31, 0x69,
158             0x03, 0x31, 0x73, 0xa9, 0x0a, 0x4a, 0x05, 0x2d, 0x55, 0x2d, 0x09,
159             0x5a, 0x01, 0xd5, 0x48, 0xb4, 0x09, 0x68, 0x89, 0x54, 0x0b, 0xa4,
160             0x0a, 0xa5, 0x6a, 0x95, 0x04, 0xad, 0x08, 0x6a, 0x44, 0xda, 0x04,
161             0x74, 0x05, 0xb0, 0x25, 0x54, 0x03 };
162
163     /**
164      * 用于保存24节气
165      */
166     private static String[] principleTermNames = { "大寒", "雨水", "春分", "谷雨",
167             "小满", "夏至", "大暑", "处暑", "秋分", "霜降", "小雪", "冬至" };
168     /**
169      * 用于保存24节气
170      */
171     private static String[] sectionalTermNames = { "小寒", "立春", "惊蛰", "清明",
172             "立夏", "芒种", "小暑", "立秋", "白露", "寒露", "立冬", "大雪" };
173
174     public SolarTermsUtil(Calendar calendar) {
175         gregorianYear = calendar.get(Calendar.YEAR);
176         gregorianMonth = calendar.get(Calendar.MONTH) + 1;
177         gregorianDate = calendar.get(Calendar.DATE);
178         computeChineseFields();
179         computeSolarTerms();
180     }
181
182     public int computeChineseFields() {
183         if (gregorianYear < 1901 || gregorianYear > 2100)
184             return 1;
185         int startYear = baseYear;
186         int startMonth = baseMonth;
187         int startDate = baseDate;
188         chineseYear = baseChineseYear;
189         chineseMonth = baseChineseMonth;
190         chineseDate = baseChineseDate;
191         // 第二个对应日,用以提高计算效率
192         // 公历 2000 年 1 月 1 日,对应农历 4697 年 11 月 25 日
193         if (gregorianYear >= 2000) {
194             startYear = baseYear + 99;
195             startMonth = 1;
196             startDate = 1;
197             chineseYear = baseChineseYear + 99;
198             chineseMonth = 11;
199             chineseDate = 25;
200         }
201         int daysDiff = 0;
202         for (int i = startYear; i < gregorianYear; i++) {
203             daysDiff += 365;
204             if (isGregorianLeapYear(i))
205                 daysDiff += 1; // leap year
206         }
207         for (int i = startMonth; i < gregorianMonth; i++) {
208             daysDiff += daysInGregorianMonth(gregorianYear, i);
209         }
210         daysDiff += gregorianDate - startDate;
211
212         chineseDate += daysDiff;
213         int lastDate = daysInChineseMonth(chineseYear, chineseMonth);
214         int nextMonth = nextChineseMonth(chineseYear, chineseMonth);
215         while (chineseDate > lastDate) {
216             if (Math.abs(nextMonth) < Math.abs(chineseMonth))
217                 chineseYear++;
218             chineseMonth = nextMonth;
219             chineseDate -= lastDate;
220             lastDate = daysInChineseMonth(chineseYear, chineseMonth);
221             nextMonth = nextChineseMonth(chineseYear, chineseMonth);
222         }
223         return 0;
224     }
225
226     public int computeSolarTerms() {
227         if (gregorianYear < 1901 || gregorianYear > 2100)
228             return 1;
229         sectionalTerm = sectionalTerm(gregorianYear, gregorianMonth);
230         principleTerm = principleTerm(gregorianYear, gregorianMonth);
231         return 0;
232     }
233
234     public static int sectionalTerm(int y, int m) {
235         if (y < 1901 || y > 2100)
236             return 0;
237         int index = 0;
238         int ry = y - baseYear + 1;
239         while (ry >= sectionalTermYear[m - 1][index])
240             index++;
241         int term = sectionalTermMap[m - 1][4 * index + ry % 4];
242         if ((ry == 121) && (m == 4))
243             term = 5;
244         if ((ry == 132) && (m == 4))
245             term = 5;
246         if ((ry == 194) && (m == 6))
247             term = 6;
248         return term;
249     }
250
251     public static int principleTerm(int y, int m) {
252         if (y < 1901 || y > 2100)
253             return 0;
254         int index = 0;
255         int ry = y - baseYear + 1;
256         while (ry >= principleTermYear[m - 1][index])
257             index++;
258         int term = principleTermMap[m - 1][4 * index + ry % 4];
259         if ((ry == 171) && (m == 3))
260             term = 21;
261         if ((ry == 181) && (m == 5))
262             term = 21;
263         return term;
264     }
265
266     /**
267      * 用于判断输入的年份是否为闰年
268      *
269      * @param year
270      *            输入的年份
271      * @return true 表示闰年
272      */
273     public static boolean isGregorianLeapYear(int year) {
274         boolean isLeap = false;
275         if (year % 4 == 0)
276             isLeap = true;
277         if (year % 100 == 0)
278             isLeap = false;
279         if (year % 400 == 0)
280             isLeap = true;
281         return isLeap;
282     }
283
284     public static int daysInGregorianMonth(int y, int m) {
285         int d = daysInGregorianMonth[m - 1];
286         if (m == 2 && isGregorianLeapYear(y))
287             d++; // 公历闰年二月多一天
288         return d;
289     }
290
291     public static int daysInChineseMonth(int y, int m) {
292         // 注意:闰月 m < 0
293         int index = y - baseChineseYear + baseIndex;
294         int v = 0;
295         int l = 0;
296         int d = 30;
297         if (1 <= m && m <= 8) {
298             v = chineseMonths[2 * index];
299             l = m - 1;
300             if (((v >> l) & 0x01) == 1)
301                 d = 29;
302         } else if (9 <= m && m <= 12) {
303             v = chineseMonths[2 * index + 1];
304             l = m - 9;
305             if (((v >> l) & 0x01) == 1)
306                 d = 29;
307         } else {
308             v = chineseMonths[2 * index + 1];
309             v = (v >> 4) & 0x0F;
310             if (v != Math.abs(m)) {
311                 d = 0;
312             } else {
313                 d = 29;
314                 for (int i = 0; i < bigLeapMonthYears.length; i++) {
315                     if (bigLeapMonthYears[i] == index) {
316                         d = 30;
317                         break;
318                     }
319                 }
320             }
321         }
322         return d;
323     }
324
325     public static int nextChineseMonth(int y, int m) {
326         int n = Math.abs(m) + 1;
327         if (m > 0) {
328             int index = y - baseChineseYear + baseIndex;
329             int v = chineseMonths[2 * index + 1];
330             v = (v >> 4) & 0x0F;
331             if (v == m)
332                 n = -m;
333         }
334         if (n == 13)
335             n = 1;
336         return n;
337     }
338
339     // 大闰月的闰年年份
340     private static int[] bigLeapMonthYears = { 6, 14, 19, 25, 33, 36, 38, 41,
341             44, 52, 55, 79, 117, 136, 147, 150, 155, 158, 185, 193 };
342
343     /**
344      * 用于获取24节气的值
345      *
346      * @return 24节气的值
347      */
348     public String getSolartermsMsg() {
349         String str = "";
350         String gm = String.valueOf(gregorianMonth);
351         if (gm.length() == 1)
352             gm = ‘ ‘ + gm;
353         String cm = String.valueOf(Math.abs(chineseMonth));
354         if (cm.length() == 1)
355             cm = ‘ ‘ + cm;
356         String gd = String.valueOf(gregorianDate);
357         if (gd.length() == 1)
358             gd = ‘ ‘ + gd;
359         String cd = String.valueOf(chineseDate);
360         if (cd.length() == 1)
361             cd = ‘ ‘ + cd;
362         if (gregorianDate == sectionalTerm) {
363             str = " " + sectionalTermNames[gregorianMonth - 1];
364         } else if (gregorianDate == principleTerm) {
365             str = " " + principleTermNames[gregorianMonth - 1];
366         }
367         return str;
368     }
369 }

8)

StringUtil
 1 package com.example.nanchen.mydateviewdemo.view;
 2
 3 /**
 4  * @author nanchen
 5  * @date 16-8-10 上午11:39
 6  */
 7 public class StringUtil {
 8
 9     /**
10      * 判断是否为null或空值
11      *
12      * @param str
13      *            String
14      * @return true or false
15      */
16     public static boolean isNullOrEmpty(String str) {
17         return str == null || str.trim().length() == 0;
18     }
19
20     /**
21      * 判断str1和str2是否相同
22      *
23      * @param str1
24      *            str1
25      * @param str2
26      *            str2
27      * @return true or false
28      */
29     public static boolean equals(String str1, String str2) {
30         return str1 == str2 || str1 != null && str1.equals(str2);
31     }
32
33     /**
34      * 判断str1和str2是否相同(不区分大小写)
35      *
36      * @param str1
37      *            str1
38      * @param str2
39      *            str2
40      * @return true or false
41      */
42     public static boolean equalsIgnoreCase(String str1, String str2) {
43         return str1 != null && str1.equalsIgnoreCase(str2);
44     }
45
46     /**
47      * 判断字符串str1是否包含字符串str2
48      *
49      * @param str1
50      *            源字符串
51      * @param str2
52      *            指定字符串
53      * @return true源字符串包含指定字符串,false源字符串不包含指定字符串
54      */
55     public static boolean contains(String str1, String str2) {
56         return str1 != null && str1.contains(str2);
57     }
58
59     /**
60      * 判断字符串是否为空,为空则返回一个空值,不为空则返回原字符串
61      *
62      * @param str
63      *            待判断字符串
64      * @return 判断后的字符串
65      */
66     public static String getString(String str) {
67         return str == null ? "" : str;
68     }
69 }

9)

ViewUtil
  1 package com.example.nanchen.mydateviewdemo.view;
  2
  3 import android.content.Context;
  4 import android.content.res.Resources;
  5
  6 /**
  7  * 辅助类
  8  *
  9  * @author nanchen
 10  * @date 16-8-10 上午11:39
 11  */
 12 public class ViewUtil {
 13     /**
 14      * 获取屏幕的宽度
 15      * @param context
 16      * @return
 17      */
 18     public int getScreenWidth(Context context) {
 19         Resources res = context.getResources();
 20         return res.getDisplayMetrics().widthPixels;
 21     }
 22
 23     /**
 24      * 获取屏幕高度
 25      * @param context
 26      * @return
 27      */
 28     public int getScreenHeight(Context context) {
 29         Resources res = context.getResources();
 30         return res.getDisplayMetrics().heightPixels;
 31     }
 32
 33     /**
 34      * 描述:根据分辨率获得字体大小.
 35      *
 36      * @param screenWidth the screen width
 37      * @param screenHeight the screen height
 38      * @param textSize the text size
 39      * @return the int
 40      */
 41     public static int resizeTextSize(int screenWidth,int screenHeight,int textSize){
 42         float ratio =  1;
 43         try {
 44             float ratioWidth = (float)screenWidth / 480;
 45             float ratioHeight = (float)screenHeight / 800;
 46             ratio = Math.min(ratioWidth, ratioHeight);
 47         } catch (Exception e) {
 48         }
 49         return Math.round(textSize * ratio);
 50     }
 51
 52     /**
 53      *
 54      * 描述:dip转换为px
 55      * @param context
 56      * @param dipValue
 57      * @return
 58      * @throws
 59      */
 60     public static int dip2px(Context context, float dipValue) {
 61         final float scale = context.getResources().getDisplayMetrics().density;
 62         return Math.round(dipValue * scale);
 63     }
 64
 65     /**
 66      *
 67      * 描述:px转换为dip
 68      * @param context
 69      * @param pxValue
 70      * @return
 71      * @throws
 72      */
 73     public static int px2dip(Context context, float pxValue) {
 74         final float scale = context.getResources().getDisplayMetrics().density;
 75         return Math.round(pxValue / scale);
 76     }
 77
 78     /**
 79      *
 80      * 描述:px转换为sp
 81      * @param context
 82      * @param pxValue
 83      * @return
 84      * @throws
 85      */
 86     public static int px2sp(Context context, float pxValue) {
 87         final float scale = context.getResources().getDisplayMetrics().scaledDensity;
 88         return Math.round(pxValue / scale);
 89     }
 90
 91     /**
 92      *
 93      * 描述:sp转换为px
 94      * @param context
 95      * @param spValue
 96      * @return
 97      * @throws
 98      */
 99     public static int sp2px(Context context, float spValue) {
100         final float scale = context.getResources().getDisplayMetrics().scaledDensity;
101         return Math.round(spValue * scale);
102     }
103 }

10)

WeekGridAdapter
 1 package com.example.nanchen.mydateviewdemo.view;
 2
 3 import android.content.Context;
 4 import android.graphics.Color;
 5 import android.view.Gravity;
 6 import android.view.View;
 7 import android.view.ViewGroup;
 8 import android.view.ViewGroup.LayoutParams;
 9 import android.widget.BaseAdapter;
10 import android.widget.TextView;
11
12 import com.example.nanchen.mydateviewdemo.R;
13
14 /**
15  * 显示week的布局adapter
16  * @author nanchen
17  * @date 16-8-10 上午11:39
18  */
19 public class WeekGridAdapter extends BaseAdapter {
20     final String[] titles = new String[] { "日", "一", "二", "三", "四", "五", "六" };
21     private Context mContext;
22
23     public WeekGridAdapter(Context context) {
24         this.mContext = context;
25     }
26
27     @Override
28     public int getCount() {
29         return titles.length;
30     }
31
32     @Override
33     public Object getItem(int position) {
34         return titles[position];
35     }
36
37     @Override
38     public long getItemId(int position) {
39         return position;
40     }
41
42     @Override
43     public View getView(int position, View convertView, ViewGroup parent) {
44         TextView week = new TextView(mContext);
45         android.view.ViewGroup.LayoutParams week_params = new LayoutParams(
46                 android.view.ViewGroup.LayoutParams.MATCH_PARENT,
47                 android.view.ViewGroup.LayoutParams.MATCH_PARENT);
48         week.setLayoutParams(week_params);
49         week.setPadding(0, 0, 0, 0);
50         week.setGravity(Gravity.CENTER);
51         week.setFocusable(false);
52         week.setBackgroundColor(Color.TRANSPARENT);
53
54         if (position == 6) { // 周六
55             week.setBackgroundColor(R.color.date_weekend_text_color);
56             week.setTextColor(Color.WHITE);
57         } else if (position == 0) { // 周日
58             week.setBackgroundColor(R.color.date_weekend_text_color);
59             week.setTextColor(Color.WHITE);
60         } else {
61             week.setTextColor(Color.BLACK);
62         }
63         week.setText(getItem(position)+"");
64         return week;
65     }
66 }

11)

MainActivity
 1 package com.example.nanchen.mydateviewdemo;
 2
 3 import android.os.Bundle;
 4 import android.support.v7.app.AppCompatActivity;
 5 import android.widget.Toast;
 6
 7 import com.example.nanchen.mydateviewdemo.view.CalendarView;
 8 import com.example.nanchen.mydateviewdemo.view.CalendarView.OnCalendarViewListener;
 9
10 import java.text.SimpleDateFormat;
11 import java.util.ArrayList;
12 import java.util.Date;
13 import java.util.List;
14 import java.util.Locale;
15
16 public class MainActivity extends AppCompatActivity {
17
18     @Override
19     protected void onCreate(Bundle savedInstanceState) {
20         super.onCreate(savedInstanceState);
21         setContentView(R.layout.activity_main);
22
23         //在代码中
24         CalendarView calendarView = (CalendarView) findViewById(R.id.calender);
25         //设置标注日期
26         List<Date> markDates = new ArrayList<>();
27         markDates.add(new Date());
28         calendarView.setMarkDates(markDates);
29
30         //设置点击操作
31         calendarView.setOnCalendarViewListener(new OnCalendarViewListener() {
32
33             @Override
34             public void onCalendarItemClick(CalendarView view, Date date) {
35                 final SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日", Locale.CHINA);
36                 Toast.makeText(MainActivity.this, format.format(date), Toast.LENGTH_SHORT).show();
37             }
38         });
39     }
40 }

12)布局文件

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context="com.example.nanchen.mydateviewdemo.MainActivity">
 8
 9     <com.example.nanchen.mydateviewdemo.view.CalendarView
10         android:id="@+id/calender"
11         android:background="#fff"
12         android:layout_width="match_parent"
13         android:layout_height="wrap_content">
14
15     </com.example.nanchen.mydateviewdemo.view.CalendarView>
16 </RelativeLayout>

drawable包下的

month_next_selector.xml

1 <?xml version="1.0" encoding="utf-8"?>
2 <selector xmlns:android="http://schemas.android.com/apk/res/android">
3     <item android:state_pressed="false" android:drawable="@drawable/right_arrow_pre"/>
4     <item android:state_pressed="true" android:drawable="@drawable/right_arrow"/>
5 </selector>

month_pre_selector.xml

1 <?xml version="1.0" encoding="utf-8"?>
2 <selector xmlns:android="http://schemas.android.com/apk/res/android">
3     <item android:state_pressed="false" android:drawable="@drawable/left_arrow_pre"/>
4     <item android:state_pressed="true" android:drawable="@drawable/left_arrow"/>
5 </selector>

color.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3     <color name="colorPrimary">#3F51B5</color>
 4     <color name="colorPrimaryDark">#303F9F</color>
 5     <color name="colorAccent">#FF4081</color>
 6     <color name="date_pre_color">#44010101</color>
 7     <color name="date_select_color">#66d8ec</color>
 8     <color name="date_text_color">#010101</color>
 9     <color name="date_other_text_color">#dd918d8d</color>
10     <color name="date_today_text_color">#aaf43ed8</color>
11
12     <color name="date_weekend_text_color">#f27e9d</color>
13
14 </resources>

项目已同步至github:https://github.com/nanchen2251/MyCalendarViewDemo

额,楼主很蠢,就这个花了好一阵功夫,但是无私分享给大家,希望大家越来越好,如果你觉得还算有帮助,别忘了右下角点赞~~分享给你我他~

转载别忘了在醒目位置附上楼主地址哦~谢谢:http://www.cnblogs.com/liushilin/p/5759750.html

时间: 2024-08-02 10:58:36

【无私分享】干货!!!一个炫酷的自定义日历控件,摆脱日历时间选择烦恼,纯福利~的相关文章

Android自定义组件之日历控件-精美日历实现(内容、样式可扩展)

需求 我们知道,Android系统本身有自带的日历控件,网络上也有很多开源的日历控件资源,但是这些日历控件往往样式较单一,API较多,不易于在实际项目中扩展并实现出符合具体样式风格的,内容可定制的效果.本文通过自定义日历控件,实现了在内容和样式上可高度扩展的精美日历demo,有需要的Android应用开发人员可迅速移植并按需扩展实现. 在某个应用中,需要查询用户的历史考勤记录,根据实际考勤数据在日历中标记出不同的状态(如正常出勤.请假.迟到等),并在页面中显示相应的说明文字. 效果 实现的效果如

自定义组合控件和在自定义控件中使用自定义属性

今天,整理了一下我平时的笔记,写一个比较简单的自定义组合控件,仅供小白参考,大神请绕道,希望能够对大家有一些帮助 首先,得明白为什么我们需要自定义组合控件,它是因为原有控件并不能满足开发的需求,或者说并不能达到我们想要的一种效果,这个时候,就需要我们自己定义一些控件,以达到目的 ![先来看一下效果](http://img.blog.csdn.net/20160716224219109) 个人总结自定义控件的步骤: 1.先写一个布局,这里我用的是一个相对布局,我这里的相对布局就是根布局了 <?xm

DuiLib 自定义识别控件

遇到一个断点无法识别自定义的控件,运气比较好,一搜就搜出来了: 参考地址:http://www.bkjia.com/ASPjc/992050.html 主要是这个函数: CControlUI* CDialogBuilder::Create(STRINGorID xml, LPCTSTR type, IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent) 这个函数 的第一个参数指定为xml

(八)ASP.NET自定义用户控件(1)

http://blog.csdn.net/laodao1/article/details/5897366 ASP.NET自定义控件组件开发 第一章:从一个简单的控件谈起 起始开发ASP.NET自定义控件不是那么的高深,当初我开始学的时候还有点恐惧,但是慢慢就好了.学习控件的开发技术,并不一定说以后要从事控件的开发,而是让我们深入的理解掌握ASP.NET内部的机理.你会发觉,当学习完控件开发技术后,你以后开发网站时有种得心应手的感觉.我不希望一上来就讲控件开始多么多么难啊,我会用一个演化的方法来讲

开源分享三(炫酷的Android Loading动画)

开源分享三(炫酷的Android Loading动画) 分享GitHub上的一些Loading,为了提升产品用户体验,一个好的Loading必然是不可缺少的,对于一些耗时需要用户等待的页面来说会转移用户注意力,不会显得那么烦躁,所以你可以看到市面上一些App中的各种各样的Loading动画,从这些实现思路上可以打开你们自己的思维,没准也会有创新的Loading动画出现. android-shapeLoadingView 新版58同城加载页面动画. CircleProgress 一个效果很酷炫很创

Android 从无到有打造一个炫酷的进度条效果

从无到有打造一个炫酷的进度条效果

一个炫酷的Actionbar效果

今天在网上看到一个炫酷的Actionbar效果,一个老外做的DEMO,目前很多流行的app已经加入了这个效果. 当用户初始进入该界面的时候,为一个透明的 ActiionBar ,这样利用充分的空间显示大图片,如果用户滚动页面需要查看内容的时候,则大图收缩到 ActionBar 中. 源码下载:http://files.cnblogs.com/sage-blog/notboringactionbar.zip 参考:http://flavienlaurent.com/blog/2013/11/20/

Xamarin.Forms自定义用户界面控件实现一个HybridWebView(混合webview)

原文:Implementing a HybridWebView呈现一个特定于平台的视图 Xamarin.Forms自定义用户界面控件应该来自视图类(View class),用于在屏幕上放置布局和控件.本文演示了如何为HybridWebView(混合webview)自定义控件创建自定义渲染器,该控件演示了如何增强特定平台的web控件,以允许从JavaScript调用c#代码. 每一个Xamarin.Forms视图为每个创建本地控件实例的平台提供了相应的渲染器.当一个视图被Xamarin.Forms

自定义Imageview控件实现多种手势操作 (拖动、水平缩放、竖直缩放、等比例缩放、双击、长按)

项目中需要使用自定义控件的多种手势操作,之前在网上查阅资料的时候发现能找到的一般是只实现了其中的几种,这次就把我做的控件分享一下,人人为我,我为人人嘛,哈哈! 这个自定义控件实现的主要功能是控件的拖动和缩放(注意:不是对控件中的图片进行操作,话说很多帖子都把这两个混了),其中缩放可以按照三个方向进行,就是水平.竖直和等比例.双击操作只做了一个提示,长按加上了一个简单的弹出菜单. 抱歉的是没有足够的时间写详细注释了,如果跟你需要的功能相同就请直接调用,要是需要改代码就费点神自己读懂代码吧,看不懂的