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

可能不少的小伙伴都有看楼主昨天发的自定义日历控件,虽然实现功能不多,但也还算将就吧。

但是看了的小伙伴就很心急了,说楼主上传到gitHub的东西有问题,楼主下载来看了看,基本都没问题吧,没弄好的小伙伴自己再去我的github首页提取哦~因为我还上传了一个新的。

有的小伙伴又不满意了,楼主,你发的东西代码量那么大也搞得很麻烦,小生纵有远大理想,可思前虑后,还是不得正果,倘若楼主能指点一二便好了。

有的小伙伴说,楼主,你的东西就不能封装一下吗?封装一下,方便你我他~

有的小伙伴说,楼主,你的东西是挺不错,但是界面也略丑了吧~这里gank到22楼住的小伙伴说,中间分隔太低,信息太密集,建议添加行间距和留白,希望能做的漂亮些~

......

小主已成功gank到各位的中肯建议,但是不要慌,大家一个一个来。

大家的建议小主都非常地认可,所以楼主觉得把整个东西该封装的算法封装起来,也UI也弄得漂亮一些。

照例先给个运行图吧~

cec424205fcbfe43655c4aebb8a08de7.gif

下面给大家讲解一下我们这个自定义日历的简单思路,肯定还是使用GridView的。

由于昨天是纯定义画的UI,所以大家看起来可能有所困难,所以今天楼主简化了UI,把UI放在了xml文件中,供大家食用。

楼主不是废话多的人,具体看代码,代码中我也做了更多的注释。

1)先准备好我们的算法,我们现在把它完全分离。

闰年月的算法应该大家都懂吧。SpecialCalendar.java

三个方法,判断闰年,这个可能只要学程序前面肯定就学了的。

对于判断月份,貌似也不用多说,就一个switch语句,闰年的时候2月是29天,平年是28天。

还有一个判断某一天是星期几的,这个在Calendar中已经很明显了,但是要注意的是Month在calendar中是0-11

1 packagecom.example.nanchen.calendarviewdemo.view;2

3 importjava.util.Calendar;4

5 /**

6 * 闰年月算法7 *8 *@authornanchen9 * @date 2016-08-11 08:54:4410 *11 */

12 public classSpecialCalendar {13

14 private int daysOfMonth = 0; //某月的天数

15 private int dayOfWeek = 0; //具体某一天是星期几16

17 //判断是否为闰年

18 public boolean isLeapYear(intyear) {19 if (year % 100 == 0 && year % 400 == 0) {20 return true;21 } else if (year % 100 != 0 && year % 4 == 0) {22 return true;23 }24 return false;25 }26

27 //得到某月有多少天数

28 public int getDaysOfMonth(boolean isLeapYear, intmonth) {29 switch(month) {30 case 1:31 case 3:32 case 5:33 case 7:34 case 8:35 case 10:36 case 12:37 daysOfMonth = 31;38 break;39 case 4:40 case 6:41 case 9:42 case 11:43 daysOfMonth = 30;44 break;45 case 2:46 if(isLeapYear) {47 daysOfMonth = 29;48 } else{49 daysOfMonth = 28;50 }51

52 }53 returndaysOfMonth;54 }55

56 /**

57 * 指定某年中的某月的第一天是星期几58 */

59 public int getWeekdayOfMonth(int year, intmonth) {60 Calendar cal =Calendar.getInstance();61 cal.set(year, month - 1, 1);62 dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 1;63 returndayOfWeek;64 }65

66 }

2)然后带来的是算农历的算法。LunarCalendar.java

就算法本身而言,楼主参考了网上留下的算法。基本就是定义好这些要用的数组,然后考虑完所有的情况。

这里需要心细严谨一些,毕竟你或许错一个参数,一个值就会让你一直搞不出原因,所以写出算法不妨先在Eclipse中看看控制台运行的结果是否正确吧。

高配置随便带Android studio的童鞋当我没说。

这里需要注意的是,我们要做农历,肯定必须想到年份,闰月,闰月是哪个月,这个月有多少天,这些都是需要考虑的。

楼主这简单添加几个节日,节日大家可以随便添加哦。只是一个显示问题。

1 packagecom.example.nanchen.calendarviewdemo.view;2

3 importjava.text.ParseException;4 importjava.text.SimpleDateFormat;5 importjava.util.Date;6 importjava.util.Locale;7

8 /**

9 * 农历算法10 *11 *@authornanchen12 * @date 2016-08-11 08-57:2413 */

14 public classLunarCalendar {15 private int year; //农历的年份

16 private intmonth;17 private intday;18 private String lunarMonth; //农历的月份

19 public int leapMonth = 0; //闰的是哪个月

20

21 final static String chineseNumber[] = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"};22 static SimpleDateFormat chineseDateFormat = new SimpleDateFormat("yyyy年MM月dd日", Locale.CHINA);23 final static long[] lunarInfo = new long[]{ //24 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, //25 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, //26 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, //27 0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, //28 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, //29 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, //30 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, //31 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, //32 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, 0x095b0, //33 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //34 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, //35 0x092e0, 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, //36 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, //37 0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, //38 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, //39 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, //40 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0};41

42 //农历部分假日

43 final static String[] lunarHoliday = new String[]{"0101 春节", "0115 元宵", "0505 端午", "0707 情人", "0715 中元", "0815 中秋", "0909 重阳", "1208 腊八", "1224 小年", "0100 除夕"};44

45 //公历部分节假日

46 final static String[] solarHoliday = new String[]{ //47 "0101 元旦", "0214 情人", "0308 妇女", "0312 植树", "0315 消费者权益日", "0401 愚人", "0501 劳动", "0504 青年", //48 "0512 护士", "0601 儿童", "0701 建党", "0801 建军", "0808 父亲", "0910 教师", "0928 孔子诞辰",//49 "1001 国庆", "1006 老人", "1024 联合国日", "1112 孙中山诞辰纪念", "1220 澳门回归纪念", "1225 圣诞"};50

51 /**

52 * 传回农历 y年的总天数53 *54 *@paramy 年份55 *@return该年的总天数56 */

57 private static int yearDays(inty) {58 int i, sum = 348;59 for (i = 0x8000; i > 0x8; i >>= 1) {60 if ((lunarInfo[y - 1900] & i) != 0)61 sum += 1;62 }63 return (sum +leapDays(y));64 }65

66 /**

67 * 传回农历 y年闰月的天数68 *69 *@paramy 年份70 *@return改年闰月天数71 */

72 private static int leapDays(inty) {73 if (leapMonth(y) != 0) {74 if ((lunarInfo[y - 1900] & 0x10000) != 0)75 return 30;76 else

77 return 29;78 } else

79 return 0;80 }81

82 /**

83 * 传回农历 y年闰哪个月 1-12 , 没闰传回 084 *85 *@paramy 年份86 *@return改年闰月的月数87 */

88 private static int leapMonth(inty) {89 return (int) (lunarInfo[y - 1900] &0b1111);90 }91

92 /**

93 * 传回农历 y年m月的总天数94 *95 *@paramy 年份96 *@paramm 月份97 *@return该月份的总天数98 */

99 private static int monthDays(int y, intm) {100 if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0)101 return 29;102 else

103 return 30;104 }105

106 /**

107 * 传回农历 y年的生肖108 *109 *@paramyear 年份110 *@return生肖111 */

112 public String animalsYear(intyear) {113 final String[] Animals = new String[]{"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};114 return Animals[(year - 4) % 12];115 }116

117 /**

118 * 传入 月日的offset 传回干支, 0=甲子119 */

120 private static String cyclicalm(intnum) {121 final String[] Gan = new String[]{"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};122 final String[] Zhi = new String[]{"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};123 return (Gan[num % 10] + Zhi[num % 12]);124 }125

126 /**

127 * 传入 offset 传回干支, 0=甲子128 */

129 public String cyclical(intyear) {130 int num = year - 1900 + 36;131 return(cyclicalm(num));132 }133

134 public static String getChinaDayString(intday) {135 String chineseTen[] = {"初", "十", "廿", "卅"};136 int n = day % 10 == 0 ? 9 : day % 10 - 1;137 if (day > 30)138 return "";139 if (day == 10)140 return "初十";141 else

142 return chineseTen[day / 10] +chineseNumber[n];143 }144

145 /**

146 * 传出y年m月d日对应的农历. yearCyl3:农历年与1864的相差数 ? monCyl4:从1900年1月31日以来,闰月数147 * dayCyl5:与1900年1月31日相差的天数,再加40 ?148 *

152 */

153 public String getLunarDate(int year_log, int month_log, intday_log,154 booleanisday) {155 //@SuppressWarnings("unused")

156 intyearCyl, monCyl, dayCyl;157 //int leapMonth = 0;

158 String nowadays;159 Date baseDate = null;160 Date nowaday = null;161 try{162 baseDate = chineseDateFormat.parse("1900年1月31日");163 } catch(ParseException e) {164 e.printStackTrace(); //To change body of catch statement use165 //Options | File Templates.

166 }167

168 nowadays = year_log + "年" + month_log + "月" + day_log + "日";169 try{170 nowaday =chineseDateFormat.parse(nowadays);171 } catch(ParseException e) {172 e.printStackTrace(); //To change body of catch statement use173 //Options | File Templates.

174 }175

176 //求出和1900年1月31日相差的天数

177 int offset = (int) ((nowaday.getTime() - baseDate.getTime()) / 86400000L);178 dayCyl = offset + 40;179 monCyl = 14;180

181 //用offset减去每农历年的天数182 //计算当天是农历第几天183 //i最终结果是农历的年份184 //offset是当年的第几天

185 int iYear, daysOfYear = 0;186 for (iYear = 1900; iYear < 10000 && offset > 0; iYear++) {187 daysOfYear =yearDays(iYear);188 offset -=daysOfYear;189 monCyl += 12;190 }191 if (offset < 0) {192 offset +=daysOfYear;193 iYear--;194 monCyl -= 12;195 }196 //农历年份

197 year =iYear;198 setYear(year); //设置公历对应的农历年份

199

200 yearCyl = iYear - 1864;201 leapMonth = leapMonth(iYear); //闰哪个月,1-12

202 boolean leap = false;203

204 //用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天

205 int iMonth, daysOfMonth = 0;206 for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) {207 //闰月

208 if (leapMonth > 0 && iMonth == (leapMonth + 1) && !leap) {209 --iMonth;210 leap = true;211 daysOfMonth =leapDays(year);212 } else

213 daysOfMonth =monthDays(year, iMonth);214

215 offset -=daysOfMonth;216 //解除闰月

217 if (leap && iMonth == (leapMonth + 1))218 leap = false;219 if (!leap)220 monCyl++;221 }222 //offset为0时,并且刚才计算的月份是闰月,要校正

223 if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) {224 if(leap) {225 leap = false;226 } else{227 leap = true;228 --iMonth;229 --monCyl;230 }231 }232 //offset小于0时,也要校正

233 if (offset < 0) {234 offset +=daysOfMonth;235 --iMonth;236 --monCyl;237 }238 month =iMonth;239 setLunarMonth(chineseNumber[month - 1] + "月"); //设置对应的阴历月份

240 day = offset + 1;241

242 if (!isday) {243 //如果日期为节假日则阴历日期则返回节假日244 //setLeapMonth(leapMonth);

245 for (int i = 0; i < solarHoliday.length; i++) {246 //返回公历节假日名称

247 String sd = solarHoliday[i].split(" ")[0]; //节假日的日期

248 String sdv = solarHoliday[i].split(" ")[1]; //节假日的名称

249 String smonth_v = month_log + "";250 String sday_v = day_log + "";251 String smd = "";252 if (month_log < 10) {253 smonth_v = "0" +month_log;254 }255 if (day_log < 10) {256 sday_v = "0" +day_log;257 }258 smd = smonth_v +sday_v;259 if(sd.trim().equals(smd.trim())) {260 returnsdv;261 }262 }263

264 for (int i = 0; i < lunarHoliday.length; i++) {265 //返回农历节假日名称

266 String ld = lunarHoliday[i].split(" ")[0]; //节假日的日期

267 String ldv = lunarHoliday[i].split(" ")[1]; //节假日的名称

268 String lmonth_v = month + "";269 String lday_v = day + "";270 String lmd = "";271 if (month < 10) {272 lmonth_v = "0" +month;273 }274 if (day < 10) {275 lday_v = "0" +day;276 }277 lmd = lmonth_v +lday_v;278 if(ld.trim().equals(lmd.trim())) {279 returnldv;280 }281 }282 }283 if (day == 1)284 return chineseNumber[month - 1] + "月";285 else

286 returngetChinaDayString(day);287

288 }289

290 publicString toString() {291 if (chineseNumber[month - 1] == "一" && getChinaDayString(day) == "初一")292 return "农历" + year + "年";293 else if (getChinaDayString(day) == "初一")294 return chineseNumber[month - 1] + "月";295 else

296 returngetChinaDayString(day);297 //return year + "年" + (leap ? "闰" : "") + chineseNumber[month - 1] +298 //"月" + getChinaDayString(day);

299 }300

301 //

302 //public static void main(String[] args) {303 //System.out.println(new304 //LunarCalendar().getLunarDate(2012, 1, 23));305 //}

306

307

308 public intgetLeapMonth() {309 returnleapMonth;310 }311

312 public void setLeapMonth(intleapMonth) {313 this.leapMonth =leapMonth;314 }315

316 /**

317 * 得到当前日期对应的阴历月份318 *319 *@return

320 */

321 publicString getLunarMonth() {322 returnlunarMonth;323 }324

325 public voidsetLunarMonth(String lunarMonth) {326 this.lunarMonth =lunarMonth;327 }328

329 /**

330 * 得到当前年对应的农历年份331 *332 *@return

333 */

334 public intgetYear() {335 returnyear;336 }337

338 public void setYear(intyear) {339 this.year =year;340 }341 }

3)为了设置点击事件,这里就分离一个接口出来吧。

ClickDataListener.java

1 packagecom.example.nanchen.calendarviewdemo.view;2

3 /**

4 * 选中日期的监听事件5 *6 *@authornanchen7 * @date 2016-08-11 09:14:218 */

9 public interfaceClickDataListener {10 /**

11 * 点击日期day的点击事件监听12 *@paramyear 年13 *@parammonth 月14 *@paramday 日15 */

16 void onClickData(int year, int month, intday);17 }

这里暂且只有一个点击事件,这个东西大家可以自行创新。

4)这里定义一个格式,可能大家格式都不一样,自己弄呗。

FormatDate.java

1 packagecom.example.nanchen.calendarviewdemo.view;2

3 /**

4 *@authornanchen5 * @date 16-8-12 上午8:156 */

7 public classFormatDate {8 public static String DATE_FORMAT = "yyyy-MM-dd";9 }

5)先来看看Adapter的代码,毕竟只有Adapter做好了,才能好好显示。

这里大家需要注意的是设置点击左右和滑动的时候都要显示上月或者下月,这个其实之前楼主写了一个TimeUtils的工具类。

这个可以通过Calendar里面的set方法来解决的,里面有两个参数。

这里先给大家看看我写的两个方法,与本例无关哦。

/*** 获得指定日期的前一月

*@paramspecifiedDay 指定的字符串日期 格式:yyyy-MM

*@return指定的前一月*/

public staticString getSpecifiedMonthBefore(String specifiedDay){

Calendar c=Calendar.getInstance();

Date date= null;try{

date= new SimpleDateFormat("yyyy-MM").parse(specifiedDay);

}catch(ParseException e) {

e.printStackTrace();

}

c.setTime(date);int month =c.get(Calendar.MONTH);

c.set(Calendar.MONTH,month-1);return new SimpleDateFormat("yyyy-MM").format(c.getTime());

}/*** 获得指定日期的后一月

*@paramspecifiedDay 指定的字符串日期 格式:yyyy-MM

*@return指定的后一月*/

public staticString getSpecifiedMonthAfter(String specifiedDay){

Calendar c=Calendar.getInstance();

Date date=null;try{

date= new SimpleDateFormat("yyyy-MM").parse(specifiedDay);

}catch(ParseException e) {

e.printStackTrace();

}

c.setTime(date);int month =c.get(Calendar.MONTH);

c.set(Calendar.MONTH,month+1);return new SimpleDateFormat("yyyy-MM").format(c.getTime());

}

上面只是教大家如何达到上月下月的效果,其实同样你可以通过Calendar和format方式对day和year等其他做同样的功能实现,大家可能以后还是有用的。

下面是Adapter,我想大家应该都很明白吧?就用new Date获取当前日期,然后字符串split分离成小数组,然后获取年月日,获取年月日方式不限,很多的。

要说到显示还是得看我们的getView,毕竟Adapter的精髓就在这个方法里,它可以觉得你到底是用怎么显示,这里楼主抛弃了以前画的方法,直接搞一个xml,把大小限制了,这样就不会像昨天那样布局密集,而丑了。

布局很简单啦。

1 <?xml version="1.0" encoding="utf-8"?>

2

3 android:layout_width="match_parent"

4 android:layout_height="match_parent"

5 android:background="#FFFFFF" >

6

7

9 android:layout_width="45dp"

10 android:layout_height="55dp"

11 android:gravity="center" />

12

13

我们在getView中设置了颜色等属性。并把非当前月设置为暗色,不可点击。

然后对于week做一些处理,好的,Adapter就OK了。

1 packagecom.example.nanchen.calendarviewdemo.view;2

3 importandroid.content.Context;4 importandroid.content.res.Resources;5 importandroid.graphics.Color;6 importandroid.text.SpannableString;7 importandroid.text.Spanned;8 importandroid.text.TextUtils;9 importandroid.text.style.RelativeSizeSpan;10 importandroid.text.style.StyleSpan;11 importandroid.util.Log;12 importandroid.view.LayoutInflater;13 importandroid.view.View;14 importandroid.view.ViewGroup;15 importandroid.widget.BaseAdapter;16 importandroid.widget.TextView;17

18 importcom.example.nanchen.calendarviewdemo.R;19

20 importjava.text.SimpleDateFormat;21 importjava.util.Date;22 importjava.util.Locale;23

24 /**

25 * 日历GridView中的每一个item显示的文本26 *27 *@authornanchen28 * @date 2016-08-11 10:14:5229 */

30 public class CalendarAdapter extendsBaseAdapter {31 private boolean isLeapYear = false; //是否为闰年

32 private int daysOfMonth = 0; //某月的天数

33 private int dayOfWeek = 0; //具体某一天是星期几

34 private int lastDaysOfMonth = 0; //上一个月的总天数

35 privateContext context;36 private String[] dayNumber = new String[42]; //一个GridView中的日期存入此数组中,因为一般日历都是6行7列

37 private SpecialCalendar sc = null;38 private LunarCalendar lc = null;39 private Resources res = null;40 private int currentYear = 0;41 private int currentMonth = 0;42 private int currentDay = 0;43

44 private SimpleDateFormat sdf = new SimpleDateFormat(FormatDate.DATE_FORMAT, Locale.CHINA);//格式化日期格式

45 private String showYear = ""; //用于在头部显示的年份

46 private String showMonth = ""; //用于在头部显示的月份

47 private String animalsYear = "";48 private String leapMonth = ""; //闰哪一个月

49 private String cyclical = ""; //天干地支50 //系统当前时间

51 private String sysDate = "";52 private String sys_year = "";53 private String sys_month = "";54 private String sys_day = "";55 private int colorDataPosition = -1;56 private boolean isClickData = false;57

58 publicCalendarAdapter() {59 Date date = newDate();60 sysDate = sdf.format(date); //当期日期

61 sys_year = sysDate.split("-")[0];62 sys_month = sysDate.split("-")[1];63 sys_day = sysDate.split("-")[2];64

65 }66

67 public CalendarAdapter(Context context, Resources rs, intjumpMonth,68 int jumpYear, int year_c, int month_c, intday_c) {69 this();70 this.context =context;71 sc = newSpecialCalendar();72 lc = newLunarCalendar();73 this.res =rs;74

75 int stepYear = year_c +jumpYear;76 int stepMonth = month_c +jumpMonth;77 if (stepMonth > 0) {78 //往下一个月滑动

79 if (stepMonth % 12 == 0) {80 stepYear = year_c + stepMonth / 12 - 1;81 stepMonth = 12;82 } else{83 stepYear = year_c + stepMonth / 12;84 stepMonth = stepMonth % 12;85 }86 } else{87 //往上一个月滑动

88 stepYear = year_c - 1 + stepMonth / 12;89 stepMonth = stepMonth % 12 + 12;90 if (stepMonth % 12 == 0) {91

92 }93 }94

95 currentYear = stepYear; //得到当前的年份

96 currentMonth = stepMonth; //得到本月97 //(jumpMonth为滑动的次数,每滑动一次就增加一月或减一月)

98 currentDay = day_c; //得到当前日期是哪天

99

100 getCalendar(currentYear, currentMonth);101

102 }103

104 public CalendarAdapter(Context context, Resources rs, int year, intmonth,105 intday) {106 this();107 this.context =context;108 sc = newSpecialCalendar();109 lc = newLunarCalendar();110 this.res =rs;111 currentYear = year;//得到跳转到的年份

112 currentMonth = month; //得到跳转到的月份

113 currentDay = day; //得到跳转到的天

114 getCalendar(currentYear, currentMonth);115 }116

117 @Override118 public intgetCount() {119 returndayNumber.length;120 }121

122 @Override123 public Object getItem(intposition) {124 returndayNumber[position];125 }126

127 @Override128 public long getItemId(intposition) {129 returnposition;130 }131

132 @Override133 public View getView(intposition, View convertView, ViewGroup parent) {134

135 if (convertView == null) {136 convertView = LayoutInflater.from(context).inflate(R.layout.calen_calendar_item, parent,false);137 }138 TextView textView =(TextView) convertView.findViewById(R.id.tvtext);139 String d = dayNumber[position].split("\\.")[0];140 String dv = dayNumber[position].split("\\.")[1];141

142 SpannableString sp = new SpannableString(d + "\n" +dv);143 sp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0,144 d.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);145 sp.setSpan(new RelativeSizeSpan(1.2f), 0, d.length(),146 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);147 if (dv != null || !TextUtils.isEmpty(dv)) {148 sp.setSpan(new RelativeSizeSpan(0.75f), d.length() + 1,149 dayNumber[position].length(),150 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);151 }152 textView.setText(sp);153 textView.setTextColor(Color.GRAY);154

155 if (position < daysOfMonth + dayOfWeek && position >=dayOfWeek) {156 //当前月信息显示

157 textView.setTextColor(Color.BLACK);//当月字体设黑158 //drawable = new ColorDrawable(Color.rgb(23, 126, 214));

159 if (position % 7 == 0 || position % 7 == 6) {160 //当前月信息显示

161 textView.setTextColor(Color.rgb(23, 126, 214));//当月字体设黑

162 }163 }164

165 if (colorDataPosition ==position) {166 //设置当天的背景

167 textView.setTextColor(Color.WHITE);168

169 textView.setBackgroundResource(R.drawable.bg_circle);170 } else{171 textView.setBackgroundColor(res.getColor(android.R.color.transparent));172 }173 returnconvertView;174 }175

176 //得到某年的某月的天数且这月的第一天是星期几

177 private void getCalendar(int year, intmonth) {178 isLeapYear = sc.isLeapYear(year); //是否为闰年

179 daysOfMonth = sc.getDaysOfMonth(isLeapYear, month); //某月的总天数

180 dayOfWeek = sc.getWeekdayOfMonth(year, month); //某月第一天为星期几

181 lastDaysOfMonth = sc.getDaysOfMonth(isLeapYear, month - 1); //上一个月的总天数

182 getweek(year, month);183 }184

185 //将一个月中的每一天的值添加入数组dayNuber中

186 private void getweek(int year, intmonth) {187 int j = 1;188 String lunarDay = "";189 //得到当前月的所有日程日期(这些日期需要标记)

190 for (int i = 0; i < dayNumber.length; i++) {191 if (i < dayOfWeek) { //前一个月

192 int temp = lastDaysOfMonth - dayOfWeek + 1;193 lunarDay = lc.getLunarDate(year, month - 1, temp + i, false);194 dayNumber[i] = (temp + i) + "." +lunarDay;195

196 } else if (i < daysOfMonth + dayOfWeek) { //本月

197 String day = String.valueOf(i - dayOfWeek + 1); //得到的日期

198 lunarDay = lc.getLunarDate(year, month, i - dayOfWeek + 1,199 false);200 dayNumber[i] = i - dayOfWeek + 1 + "." +lunarDay;201 //对于当前月才去标记当前日期

202 if(sys_year.equals(String.valueOf(year))203 &&sys_month.equals(String.valueOf(month))204 &&sys_day.equals(day)) {205 //标记当前日期

206 colorDataPosition =i;207 }208 setShowYear(String.valueOf(year));209 setShowMonth(String.valueOf(month));210 setAnimalsYear(lc.animalsYear(year));211 setLeapMonth(lc.leapMonth == 0 ? "": String212 .valueOf(lc.leapMonth));213 setCyclical(lc.cyclical(year));214 } else { //下一个月

215 lunarDay = lc.getLunarDate(year, month + 1, j, false);216 dayNumber[i] = j + "." +lunarDay;217 j++;218 }219 }220

221 String abc = "";222 for (int i = 0; i < dayNumber.length; i++) {223 abc = abc + dayNumber[i] + ":";224 }225 Log.d("DAYNUMBER", abc);226

227 }228

229 /**

230 * 点击每一个item时返回item中的日期231 *232 *@paramposition233 *@return

234 */

235 public String getDateByClickItem(intposition) {236 returndayNumber[position];237 }238

239 /**

240 * 在点击gridView时,得到这个月中第一天的位置241 *242 *@return

243 */

244 public intgetStartPositon() {245 return dayOfWeek + 7;246 }247

248 /**

249 * 在点击gridView时,得到这个月中最后一天的位置250 *251 *@return

252 */

253 public intgetEndPosition() {254 return (dayOfWeek + daysOfMonth + 7) - 1;255 }256

257 publicString getShowYear() {258 returnshowYear;259 }260

261 public voidsetShowYear(String showYear) {262 this.showYear =showYear;263 }264

265 publicString getShowMonth() {266 returnshowMonth;267 }268

269 public voidsetShowMonth(String showMonth) {270 this.showMonth =showMonth;271 }272

273 publicString getAnimalsYear() {274 returnanimalsYear;275 }276

277 public voidsetAnimalsYear(String animalsYear) {278 this.animalsYear =animalsYear;279 }280

281 publicString getLeapMonth() {282 returnleapMonth;283 }284

285 public voidsetLeapMonth(String leapMonth) {286 this.leapMonth =leapMonth;287 }288

289 publicString getCyclical() {290 returncyclical;291 }292

293 public voidsetCyclical(String cyclical) {294 this.cyclical =cyclical;295 }296

297 /**

298 *@paramposition299 * 设置点击的日期的颜色位置300 */

301 public void setColorDataPosition(intposition) {302 if (position >= dayOfWeek && position < daysOfMonth +dayOfWeek) {303 colorDataPosition =position;304 notifyDataSetChanged();305 }306 }307 }

6)重头戏还是这个MyCalendarView.java,毕竟,你其他的东西都是打辅助的,到后面,大家要用的还不是这个类。

MyCalendarView.java

1 packagecom.example.nanchen.calendarviewdemo.view;2

3 importandroid.app.Activity;4 importandroid.content.Context;5 importandroid.graphics.Color;6 importandroid.graphics.drawable.ColorDrawable;7 importandroid.util.AttributeSet;8 importandroid.util.Log;9 importandroid.view.Display;10 importandroid.view.GestureDetector;11 importandroid.view.GestureDetector.SimpleOnGestureListener;12 importandroid.view.Gravity;13 importandroid.view.MotionEvent;14 importandroid.view.View;15 importandroid.view.View.OnClickListener;16 importandroid.view.WindowManager;17 importandroid.view.animation.AnimationUtils;18 importandroid.widget.AdapterView;19 importandroid.widget.AdapterView.OnItemClickListener;20 importandroid.widget.GridView;21 importandroid.widget.ImageView;22 importandroid.widget.LinearLayout;23 importandroid.widget.TextView;24 importandroid.widget.ViewFlipper;25

26 importcom.example.nanchen.calendarviewdemo.R;27

28 importjava.text.SimpleDateFormat;29 importjava.util.Date;30 importjava.util.Locale;31

32

33 /**

34 * 自定义的日历控件35 *36 *@authornanchen37 * @date 2016-08-11 09:44:2738 */

39 public class MyCalendarView extends LinearLayout implementsOnClickListener {40

41 private final String TAG = MyCalendarView.class.getSimpleName();42 private int year_c = 0;//今天的年份

43 private int month_c = 0;//今天的月份

44 private int day_c = 0;//今天的日期

45 private String currentDate = "";//当前日期

46 privateContext mContext;47 private TextView currentMonth;//显示日期

48 private ImageView prevMonth;//去上一个月

49 private ImageView nextMonth;//去下一个月

50 private int gvFlag = 0;51 private GestureDetector gestureDetector = null;//用户手势检测

52 private CalendarAdapter adapter = null;//适配器

53 private ViewFlipper flipper = null;54 private GridView gridView = null;55 private static int jumpMonth = 0; //每次滑动,增加或减去一个月,默认为0(即显示当前月)

56 private static int jumpYear = 0; //滑动跨越一年,则增加或者减去一年,默认为0(即当前年)

57 privateClickDataListener clickDataListener;58

59 publicMyCalendarView(Context context) {60 this(context, null);61 }62

63 publicMyCalendarView(Context context, AttributeSet attrs) {64 super(context, attrs);65 mContext =context;66 initView();67 }68

69 /**

70 * 初始化布局71 */

72 private voidinitView() {73 //加载布局,一个头布局,一个横向的星期布局,下面一个ViewFlipper用于滑动

74 View view = View.inflate(mContext, R.layout.calen_calendar, this);75 currentMonth =(TextView) view.findViewById(R.id.currentMonth);76 prevMonth =(ImageView) view.findViewById(R.id.prevMonth);77 nextMonth =(ImageView) view.findViewById(R.id.nextMonth);78 setListener();79 setCurrentDay();80 gestureDetector = new GestureDetector(mContext, newMyGestureListener());81 flipper =(ViewFlipper) findViewById(R.id.flipper);82 flipper.removeAllViews();83 adapter = newCalendarAdapter(mContext, getResources(), jumpMonth,84 jumpYear, year_c, month_c, day_c);85 addGridView();86 gridView.setAdapter(adapter);87 flipper.addView(gridView, 0);88 addTextToTopTextView(currentMonth);89 }90

91 private voidsetListener() {92 prevMonth.setOnClickListener(this);93 nextMonth.setOnClickListener(this);94

95 }96

97 public voidsetClickDataListener(ClickDataListener clickDataListener) {98 this.clickDataListener =clickDataListener;99 }100

101 private voidsetCurrentDay() {102 Date date = newDate();103 SimpleDateFormat sdf = newSimpleDateFormat(FormatDate.DATE_FORMAT, Locale.CHINA);104 currentDate = sdf.format(date); //当期日期

105 year_c = Integer.parseInt(currentDate.split("-")[0]);106 month_c = Integer.parseInt(currentDate.split("-")[1]);107 day_c = Integer.parseInt(currentDate.split("-")[2]);108 }109

110 /**

111 * 移动到下一个月112 *113 *@paramgvFlag114 */

115 private void enterNextMonth(intgvFlag) {116 addGridView(); //添加一个gridView

117 jumpMonth++; //下一个月

118 adapter = new CalendarAdapter(mContext, this.getResources(), jumpMonth,119 jumpYear, year_c, month_c, day_c);120 gridView.setAdapter(adapter);121 addTextToTopTextView(currentMonth); //移动到下一月后,将当月显示在头标题中

122 gvFlag++;123 flipper.addView(gridView, gvFlag);124 flipper.setInAnimation(AnimationUtils.loadAnimation(mContext,125 R.anim.push_left_in));126 flipper.setOutAnimation(AnimationUtils.loadAnimation(mContext,127 R.anim.push_left_out));128 flipper.showNext();129 flipper.removeViewAt(0);130 }131

132 /**

133 * 移动到上一个月134 *135 *@paramgvFlag136 */

137 private void enterPrevMonth(intgvFlag) {138 addGridView(); //添加一个gridView

139 jumpMonth--; //上一个月

140

141 adapter = new CalendarAdapter(mContext, this.getResources(), jumpMonth,142 jumpYear, year_c, month_c, day_c);143 gridView.setAdapter(adapter);144 gvFlag++;145 addTextToTopTextView(currentMonth); //移动到上一月后,将当月显示在头标题中

146 flipper.addView(gridView, gvFlag);147

148 flipper.setInAnimation(AnimationUtils.loadAnimation(mContext,149 R.anim.push_right_in));150 flipper.setOutAnimation(AnimationUtils.loadAnimation(mContext,151 R.anim.push_right_out));152 flipper.showPrevious();153 flipper.removeViewAt(0);154 }155

156 /**

157 * 添加头部的年份 闰哪月等信息158 *159 *@paramview160 */

161 private voidaddTextToTopTextView(TextView view) {162 StringBuffer textDate = newStringBuffer();163 //draw = getResources().getDrawable(R.drawable.top_day);164 //view.setBackgroundDrawable(draw);

165 textDate.append(adapter.getShowYear()).append("年")166 .append(adapter.getShowMonth()).append("月").append("\t");167 view.setText(textDate);168 }169

170 private voidaddGridView() {171 LayoutParams params = newLayoutParams(172 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);173 //取得屏幕的宽度和高度

174 WindowManager windowManager =((Activity) mContext).getWindowManager();175 Display display =windowManager.getDefaultDisplay();176 int Width =display.getWidth();177 int Height =display.getHeight();178

179 gridView = newGridView(mContext);180 gridView.setNumColumns(7);181 gridView.setColumnWidth(40);182 //gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);

183 if (Width == 720 && Height == 1280) {184 gridView.setColumnWidth(40);185 }186 gridView.setGravity(Gravity.CENTER_VERTICAL);187 gridView.setSelector(newColorDrawable(Color.TRANSPARENT));188 //去除gridView边框

189 gridView.setVerticalSpacing(0);190 gridView.setHorizontalSpacing(0);191 gridView.setOnTouchListener(newOnTouchListener() {192 //将gridview中的触摸事件回传给gestureDetector

193

194 public booleanonTouch(View v, MotionEvent event) {195 //TODO Auto-generated method stub

196 returngestureDetector.onTouchEvent(event);197 }198 });199

200 gridView.setOnItemClickListener(newOnItemClickListener() {201

202 @Override203 public void onItemClick(AdapterView>arg0, View arg1,204 int position, longarg3) {205 //TODO Auto-generated method stub206 //点击任何一个item,得到这个item的日期(排除点击的是周日到周六(点击不响应))

207 int startPosition =adapter.getStartPositon();208 int endPosition =adapter.getEndPosition();209 if (startPosition <= position + 7

210 && position <= endPosition - 7) {211 int scheduleDay =Integer.parseInt(adapter.getDateByClickItem(position)212 .split("\\.")[0]); //这一天的阳历

213 int scheduleYear =Integer.parseInt(adapter.getShowYear());214 int scheduleMonth =Integer.parseInt(adapter.getShowMonth());215 ((CalendarAdapter) arg0.getAdapter())216 .setColorDataPosition(position);217 if (clickDataListener != null) {218 clickDataListener.onClickData(scheduleYear,219 scheduleMonth, scheduleDay);220 }221 }222 }223 });224 gridView.setLayoutParams(params);225 }226

227 @Override228 public voidonClick(View v) {229 switch(v.getId()) {230 case R.id.nextMonth: //下一个月

231 enterNextMonth(gvFlag);232 Log.d(TAG, "gvFlag=" +gvFlag);233 break;234 case R.id.prevMonth: //上一个月

235 enterPrevMonth(gvFlag);236 break;237

238 }239

240 }241

242 private static class MyGestureListener extendsSimpleOnGestureListener {243 privateMyCalendarView calendarView;244

245 @Override246 public boolean onFling(MotionEvent e1, MotionEvent e2, floatvelocityX,247 floatvelocityY) {248 int gvFlag = 0; //每次添加gridview到viewflipper中时给的标记

249 if (e1.getX() - e2.getX() > 120) {250 //像左滑动

251 calendarView.enterNextMonth(gvFlag);252 return true;253 } else if (e1.getX() - e2.getX() < -120) {254 //向右滑动

255 calendarView.enterPrevMonth(gvFlag);256 return true;257 }258 return false;259 }260 }261 }

这个,这个类没啥难的吧?看不懂?就跟一般的Activity处理一样,绑定布局,设置监听,做一些交互。

额,对,昨天写这个的时候搞得太复杂太复杂了。今天楼主全部放到xml文件中去了啦啦啦。

而且上面的布局和周几都不用刷新的,这不,直接放在Xml中定死就可以了嘛。

1 <?xml version="1.0" encoding="utf-8"?>

2

3 android:layout_width="match_parent"

4 android:layout_height="match_parent"

5 android:orientation="vertical" >

6

7

9 android:layout_height="wrap_content"

10 android:orientation="horizontal" >

11

12

14 android:layout_width="0dp"

15 android:layout_height="wrap_content"

16 android:layout_gravity="center"

17 android:layout_weight="1"

18 android:src="@drawable/pre_month_selector" />

19

20

22 android:layout_width="0dp"

23 android:layout_height="35dp"

24 android:layout_weight="3"

25 android:gravity="center"

26 android:text="2016年8月"

27 android:textColor="#177ed6"

28 android:textSize="18dp" />

29

30

32 android:layout_width="0dp"

33 android:layout_height="wrap_content"

34 android:layout_gravity="center"

35 android:layout_weight="1"

36 android:src="@drawable/next_month_selector" />

37

38

39

40

41

43 android:layout_height="20dp"

44 android:background="#ffffffff" >

45

46

48 android:text="日"

49 android:textColor="#177ed6" />

50

51

53 android:text="一" />

54

55

57 android:text="二" />

58

59

61 android:text="三" />

62

63

65 android:text="四" />

66

67

69 android:text="五" />

70

71

73 android:text="六"

74 android:textColor="#177ed6" />

75

76

77

79 android:layout_height="1dp"

80 android:background="#ff8091a8" />

81

82

84 android:layout_width="match_parent"

85 android:layout_height="wrap_content" />

86

XML文件够简单吧~上部一个简单的title布局,中间一个水平的线性布局用于显示周几,下面一个ViewFlipper用于左右滑动。

额,两个Selector

pre_month_selector.xml

1 <?xml version="1.0" encoding="utf-8"?>

2

3

4

5

6

7

next_month_selector.xml

1 <?xml version="1.0" encoding="utf-8"?>

2

3

4

5

6

7

7)使用,MainActivity.java

1 packagecom.example.nanchen.calendarviewdemo;2

3 importandroid.os.Bundle;4 importandroid.support.v7.app.AppCompatActivity;5 importandroid.widget.Toast;6

7 importcom.example.nanchen.calendarviewdemo.view.MyCalendarView;8 importcom.example.nanchen.calendarviewdemo.view.ClickDataListener;9

10 importjava.util.Locale;11

12 /**

13 *@authornanchen14 * @date 2016-08-11 10:48:2115 */

16 public class MainActivity extendsAppCompatActivity {17

18 @Override19 protected voidonCreate(Bundle savedInstanceState) {20 super.onCreate(savedInstanceState);21 setContentView(R.layout.activity_main);22

23 MyCalendarView myCalendarView =(MyCalendarView) findViewById(R.id.main_calendar);24 myCalendarView.setClickDataListener(newClickDataListener() {25 @Override26 public void onClickData(int year, int month, intday) {27 String date = String.format(Locale.CHINA,"%04d年%02d月%02d日",year,month,day);28 Toast.makeText(MainActivity.this,date,Toast.LENGTH_SHORT).show();29 }30 });31 }32 }

布局文件

1 <?xml version="1.0" encoding="utf-8"?>

2

4 xmlns:tools="http://schemas.android.com/tools"

5 android:layout_width="match_parent"

6 android:layout_height="match_parent"

7 android:orientation="vertical"

8 tools:context="com.example.nanchen.calendarviewdemo.MainActivity">

9

10

12 android:layout_height="wrap_content"

13 android:id="@+id/main_calendar"/>

14

还是欢迎大家抨击,点赞,分享~你们的支持和打击是小主进步的源泉~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值