Android自定义日历控件,自带农历节假日,已经开源,即取即用~

来源:互联网 发布:北京java工程师待遇 编辑:程序博客网 时间:2024/06/08 10:24

关注本人的更多博客:http://www.cnblogs.com/liushilin/

该自定义日历控件已经开源:github地址

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

没有看的小伙伴如果有兴趣的话可以去看看:http://www.cnblogs.com/liushilin/p/5759750.html

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

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

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

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

......

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

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

照例先给个运行图吧~

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

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

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

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

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

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

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

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

复制代码
 1 package com.example.nanchen.calendarviewdemo.view; 2  3 import java.util.Calendar; 4  5 /** 6  * 闰年月算法 7  * 8  * @author nanchen 9  * @date  2016-08-11 08:54:4410  *11  */12 public class SpecialCalendar {13 14     private int daysOfMonth = 0; // 某月的天数15     private int dayOfWeek = 0; // 具体某一天是星期几16 17     // 判断是否为闰年18     public boolean isLeapYear(int year) {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, int month) {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         return daysOfMonth;54     }55 56     /**57      * 指定某年中的某月的第一天是星期几58      */59     public int getWeekdayOfMonth(int year, int month) {60         Calendar cal = Calendar.getInstance();61         cal.set(year, month - 1, 1);62         dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 1;63         return dayOfWeek;64     }65 66 }
复制代码

 

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

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

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

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

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

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

复制代码
  1 package com.example.nanchen.calendarviewdemo.view;  2   3 import java.text.ParseException;  4 import java.text.SimpleDateFormat;  5 import java.util.Date;  6 import java.util.Locale;  7   8 /**  9  * 农历算法 10  * 11  * @author nanchen 12  * @date 2016-08-11  08-57:24 13  */ 14 public class LunarCalendar { 15     private int year; // 农历的年份 16     private int month; 17     private int day; 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      * @param y 年份 55      * @return 该年的总天数 56      */ 57     private static int yearDays(int y) { 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      * @param y 年份 70      * @return 改年闰月天数 71      */ 72     private static int leapDays(int y) { 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 , 没闰传回 0 84      * 85      * @param y 年份 86      * @return 改年闰月的月数 87      */ 88     private static int leapMonth(int y) { 89         return (int) (lunarInfo[y - 1900] & 0b1111); 90     } 91  92     /** 93      * 传回农历 y年m月的总天数 94      * 95      * @param y 年份 96      * @param m 月份 97      * @return 该月份的总天数 98      */ 99     private static int monthDays(int y, int m) {100         if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0)101             return 29;102         else103             return 30;104     }105 106     /**107      * 传回农历 y年的生肖108      *109      * @param year 年份110      * @return 生肖111      */112     public String animalsYear(int year) {113         final String[] Animals = new String[]{"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};114         return Animals[(year - 4) % 12];115     }116 117     /**118      * 传入 月日的offset 传回干支, 0=甲子119      */120     private static String cyclicalm(int num) {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(int year) {130         int num = year - 1900 + 36;131         return (cyclicalm(num));132     }133 134     public static String getChinaDayString(int day) {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         else142             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      * <p/>149      * isday: 这个参数为false---日期为节假日时,阴历日期就返回节假日 ,true---不管日期是否为节假日依然返回这天对应的阴历日期150      *151      * @return152      */153     public String getLunarDate(int year_log, int month_log, int day_log,154                                boolean isday) {155         // @SuppressWarnings("unused")156         int yearCyl, 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-12202         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             } else213                 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                     return sdv;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                     return ldv;280                 }281             }282         }283         if (day == 1)284             return chineseNumber[month - 1] + "月";285         else286             return getChinaDayString(day);287 288     }289 290     public String toString() {291         if (chineseNumber[month - 1] == "一" && getChinaDayString(day) == "初一")292             return "农历" + year + "年";293         else if (getChinaDayString(day) == "初一")294             return chineseNumber[month - 1] + "月";295         else296             return getChinaDayString(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 int getLeapMonth() {309         return leapMonth;310     }311 312     public void setLeapMonth(int leapMonth) {313         this.leapMonth = leapMonth;314     }315 316     /**317      * 得到当前日期对应的阴历月份318      *319      * @return320      */321     public String getLunarMonth() {322         return lunarMonth;323     }324 325     public void setLunarMonth(String lunarMonth) {326         this.lunarMonth = lunarMonth;327     }328 329     /**330      * 得到当前年对应的农历年份331      *332      * @return333      */334     public int getYear() {335         return year;336     }337 338     public void setYear(int year) {339         this.year = year;340     }341 }
复制代码

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

ClickDataListener.java
复制代码
 1 package com.example.nanchen.calendarviewdemo.view; 2  3 /** 4  * 选中日期的监听事件 5  * 6  * @author nanchen 7  * @date   2016-08-11 09:14:21 8  */ 9 public interface ClickDataListener {10     /**11      * 点击日期day的点击事件监听12      * @param year    年13      * @param month   月14      * @param day     日15      */16     void onClickData(int year, int month, int day);17 }
复制代码

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

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

FormatDate.java
复制代码
1 package com.example.nanchen.calendarviewdemo.view;2 3 /**4  * @author nanchen5  * @date 16-8-12 上午8:156  */7 public class FormatDate {8     public static String DATE_FORMAT = "yyyy-MM-dd";9 }
复制代码

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

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

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

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

复制代码
/**     * 获得指定日期的前一月     * @param specifiedDay 指定的字符串日期  格式:yyyy-MM     * @return   指定的前一月     */    public static String 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());    }    /**     * 获得指定日期的后一月     * @param specifiedDay 指定的字符串日期  格式:yyyy-MM     * @return   指定的后一月     */    public static String 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 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     android:layout_width="match_parent" 4     android:layout_height="match_parent" 5     android:background="#FFFFFF" > 6  7     <TextView 8         android:id="@+id/tvtext" 9         android:layout_width="45dp"10         android:layout_height="55dp"11         android:gravity="center" />12 13 </LinearLayout>
复制代码

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

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

复制代码
  1 package com.example.nanchen.calendarviewdemo.view;  2   3 import android.content.Context;  4 import android.content.res.Resources;  5 import android.graphics.Color;  6 import android.text.SpannableString;  7 import android.text.Spanned;  8 import android.text.TextUtils;  9 import android.text.style.RelativeSizeSpan; 10 import android.text.style.StyleSpan; 11 import android.util.Log; 12 import android.view.LayoutInflater; 13 import android.view.View; 14 import android.view.ViewGroup; 15 import android.widget.BaseAdapter; 16 import android.widget.TextView; 17  18 import com.example.nanchen.calendarviewdemo.R; 19  20 import java.text.SimpleDateFormat; 21 import java.util.Date; 22 import java.util.Locale; 23  24 /** 25  * 日历GridView中的每一个item显示的文本 26  * 27  * @author nanchen 28  * @date  2016-08-11 10:14:52 29  */ 30 public class CalendarAdapter extends BaseAdapter { 31     private boolean isLeapYear = false; // 是否为闰年 32     private int daysOfMonth = 0; // 某月的天数 33     private int dayOfWeek = 0; // 具体某一天是星期几 34     private int lastDaysOfMonth = 0; // 上一个月的总天数 35     private Context 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     public CalendarAdapter() { 59         Date date = new Date(); 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, int jumpMonth, 68             int jumpYear, int year_c, int month_c, int day_c) { 69         this(); 70         this.context = context; 71         sc = new SpecialCalendar(); 72         lc = new LunarCalendar(); 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, int month,105             int day) {106         this();107         this.context = context;108         sc = new SpecialCalendar();109         lc = new LunarCalendar();110         this.res = rs;111         currentYear = year;// 得到跳转到的年份112         currentMonth = month; // 得到跳转到的月份113         currentDay = day; // 得到跳转到的天114         getCalendar(currentYear, currentMonth);115     }116 117     @Override118     public int getCount() {119         return dayNumber.length;120     }121 122     @Override123     public Object getItem(int position) {124         return dayNumber[position];125     }126 127     @Override128     public long getItemId(int position) {129         return position;130     }131 132     @Override133     public View getView(int position, 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         return convertView;174     }175 176     // 得到某年的某月的天数且这月的第一天是星期几177     private void getCalendar(int year, int month) {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, int month) {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      * @param position233      * @return234      */235     public String getDateByClickItem(int position) {236         return dayNumber[position];237     }238 239     /**240      * 在点击gridView时,得到这个月中第一天的位置241      * 242      * @return243      */244     public int getStartPositon() {245         return dayOfWeek + 7;246     }247 248     /**249      * 在点击gridView时,得到这个月中最后一天的位置250      * 251      * @return252      */253     public int getEndPosition() {254         return (dayOfWeek + daysOfMonth + 7) - 1;255     }256 257     public String getShowYear() {258         return showYear;259     }260 261     public void setShowYear(String showYear) {262         this.showYear = showYear;263     }264 265     public String getShowMonth() {266         return showMonth;267     }268 269     public void setShowMonth(String showMonth) {270         this.showMonth = showMonth;271     }272 273     public String getAnimalsYear() {274         return animalsYear;275     }276 277     public void setAnimalsYear(String animalsYear) {278         this.animalsYear = animalsYear;279     }280 281     public String getLeapMonth() {282         return leapMonth;283     }284 285     public void setLeapMonth(String leapMonth) {286         this.leapMonth = leapMonth;287     }288 289     public String getCyclical() {290         return cyclical;291     }292 293     public void setCyclical(String cyclical) {294         this.cyclical = cyclical;295     }296 297     /**298      * @param position299      * 设置点击的日期的颜色位置300      */301     public void setColorDataPosition(int position) {302         if (position >= dayOfWeek && position < daysOfMonth + dayOfWeek) {303             colorDataPosition = position;304             notifyDataSetChanged();305         }306     }307 }
复制代码

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

MyCalendarView.java

复制代码
  1 package com.example.nanchen.calendarviewdemo.view;  2   3 import android.app.Activity;  4 import android.content.Context;  5 import android.graphics.Color;  6 import android.graphics.drawable.ColorDrawable;  7 import android.util.AttributeSet;  8 import android.util.Log;  9 import android.view.Display; 10 import android.view.GestureDetector; 11 import android.view.GestureDetector.SimpleOnGestureListener; 12 import android.view.Gravity; 13 import android.view.MotionEvent; 14 import android.view.View; 15 import android.view.View.OnClickListener; 16 import android.view.WindowManager; 17 import android.view.animation.AnimationUtils; 18 import android.widget.AdapterView; 19 import android.widget.AdapterView.OnItemClickListener; 20 import android.widget.GridView; 21 import android.widget.ImageView; 22 import android.widget.LinearLayout; 23 import android.widget.TextView; 24 import android.widget.ViewFlipper; 25  26 import com.example.nanchen.calendarviewdemo.R; 27  28 import java.text.SimpleDateFormat; 29 import java.util.Date; 30 import java.util.Locale; 31  32  33 /** 34  * 自定义的日历控件 35  * 36  * @author nanchen 37  * @date   2016-08-11 09:44:27 38  */ 39 public class MyCalendarView extends LinearLayout implements OnClickListener { 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     private Context 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     private ClickDataListener clickDataListener; 58  59     public MyCalendarView(Context context) { 60         this(context, null); 61     } 62  63     public MyCalendarView(Context context, AttributeSet attrs) { 64         super(context, attrs); 65         mContext = context; 66         initView(); 67     } 68  69     /** 70      * 初始化布局 71      */ 72     private void initView() { 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, new MyGestureListener()); 81         flipper = (ViewFlipper) findViewById(R.id.flipper); 82         flipper.removeAllViews(); 83         adapter = new CalendarAdapter(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 void setListener() { 92         prevMonth.setOnClickListener(this); 93         nextMonth.setOnClickListener(this); 94  95     } 96  97     public void setClickDataListener(ClickDataListener clickDataListener) { 98         this.clickDataListener = clickDataListener; 99     }100 101     private void setCurrentDay() {102         Date date = new Date();103         SimpleDateFormat sdf = new SimpleDateFormat(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      * @param gvFlag114      */115     private void enterNextMonth(int gvFlag) {116         addGridView(); // 添加一个gridView117         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      * @param gvFlag136      */137     private void enterPrevMonth(int gvFlag) {138         addGridView(); // 添加一个gridView139         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      * @param view160      */161     private void addTextToTopTextView(TextView view) {162         StringBuffer textDate = new StringBuffer();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 void addGridView() {171         LayoutParams params = new LayoutParams(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 = new GridView(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(new ColorDrawable(Color.TRANSPARENT));188         // 去除gridView边框189         gridView.setVerticalSpacing(0);190         gridView.setHorizontalSpacing(0);191         gridView.setOnTouchListener(new OnTouchListener() {192             // 将gridview中的触摸事件回传给gestureDetector193 194             public boolean onTouch(View v, MotionEvent event) {195                 // TODO Auto-generated method stub196                 return gestureDetector.onTouchEvent(event);197             }198         });199 200         gridView.setOnItemClickListener(new OnItemClickListener() {201 202             @Override203             public void onItemClick(AdapterView<?> arg0, View arg1,204                     int position, long arg3) {205                 // TODO Auto-generated method stub206                 // 点击任何一个item,得到这个item的日期(排除点击的是周日到周六(点击不响应))207                 int startPosition = adapter.getStartPositon();208                 int endPosition = adapter.getEndPosition();209                 if (startPosition <= position + 7210                         && 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 void onClick(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 extends SimpleOnGestureListener {243         private MyCalendarView calendarView;244 245         @Override246         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,247                 float velocityY) {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 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     android:layout_width="match_parent" 4     android:layout_height="match_parent" 5     android:orientation="vertical" > 6  7     <LinearLayout 8         android:layout_width="match_parent" 9         android:layout_height="wrap_content"10         android:orientation="horizontal" >11 12         <ImageView13             android:id="@+id/prevMonth"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         <TextView21             android:id="@+id/currentMonth"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         <ImageView31             android:id="@+id/nextMonth"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     </LinearLayout>38 39 40     <!--周几的布局-->41     <LinearLayout42         android:layout_width="match_parent"43         android:layout_height="20dp"44         android:background="#ffffffff" >45 46         <TextView47             style="@style/weekName"48             android:text="日"49             android:textColor="#177ed6" />50 51         <TextView52             style="@style/weekName"53             android:text="一" />54 55         <TextView56             style="@style/weekName"57             android:text="二" />58 59         <TextView60             style="@style/weekName"61             android:text="三" />62 63         <TextView64             style="@style/weekName"65             android:text="四" />66 67         <TextView68             style="@style/weekName"69             android:text="五" />70 71         <TextView72             style="@style/weekName"73             android:text="六"74             android:textColor="#177ed6" />75     </LinearLayout>76 77     <View78         android:layout_width="match_parent"79         android:layout_height="1dp"80         android:background="#ff8091a8" />81 82     <ViewFlipper83         android:id="@+id/flipper"84         android:layout_width="match_parent"85         android:layout_height="wrap_content" />86 </LinearLayout>
复制代码

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

额,两个Selector

pre_month_selector.xml

复制代码
1 <?xml version="1.0" encoding="utf-8"?>2 <selector xmlns:android="http://schemas.android.com/apk/res/android">3 4     <item android:state_pressed="true" android:drawable="@drawable/triangle06_pressed"/>5     <item android:state_pressed="false" android:drawable="@drawable/triangle06"/>6 7 </selector>
复制代码

next_month_selector.xml

复制代码
1 <?xml version="1.0" encoding="utf-8"?>2 <selector xmlns:android="http://schemas.android.com/apk/res/android">3 4     <item android:state_pressed="true" android:drawable="@drawable/triangle05_pressed"/>5     <item android:state_pressed="false" android:drawable="@drawable/triangle05"/>6 7 </selector>
复制代码

7)使用,MainActivity.java

复制代码
 1 package com.example.nanchen.calendarviewdemo; 2  3 import android.os.Bundle; 4 import android.support.v7.app.AppCompatActivity; 5 import android.widget.Toast; 6  7 import com.example.nanchen.calendarviewdemo.view.MyCalendarView; 8 import com.example.nanchen.calendarviewdemo.view.ClickDataListener; 9 10 import java.util.Locale;11 12 /**13  * @author nanchen14  * @date   2016-08-11 10:48:2115  */16 public class MainActivity extends AppCompatActivity {17 18     @Override19     protected void onCreate(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(new ClickDataListener() {25             @Override26             public void onClickData(int year, int month, int day) {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 <LinearLayout 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     android:orientation="vertical" 8     tools:context="com.example.nanchen.calendarviewdemo.MainActivity"> 9 10     <com.example.nanchen.calendarviewdemo.view.MyCalendarView11         android:layout_width="match_parent"12         android:layout_height="wrap_content"13         android:id="@+id/main_calendar"/>14 </LinearLayout>
复制代码

 

更多详情源码请上github:https://github.com/nanchen2251/MyCalendarViewNewDemo

 

额,差不多啦,转载的小伙伴别忘了附上本文地址:http://www.cnblogs.com/liushilin/p/5763717.html

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

0 0
原创粉丝点击