最近的项目中遇到了一个日历,需要在日历上显示一些信息,日历有点击事件。
设计小姐姐给的效果图是这样的:实际作出来的真机截图,是这样的:
实现这个效果还是比较容易的,我是用的是RecyclerView。 比较麻烦的就是日历的计算,加上农历。布局文件代码:
复制代码
item的布局:
复制代码
PPBall是一个圆形的自定义view,可以填充颜色,可以使用图片替代,这里就是显示那个红点。使用Grid布局,一周七天。
date_list.layoutManager = GridLayoutManager(this, 7)复制代码
这个RecyclerView的数据源是一个月份的天,也就是每一天都是一个数据,这个数据是通过Calendar给出的,传到Adapter里面的Calendar已经是选好了月份的。当然还有另一部分的数据是哪些天有提示的红点,今天是几号,选中了几号,这些数据在modelHolder中。
直接上Adapter的代码,只有100行,稍纵即逝:
package com.greendami.adapter.scheduleimport android.content.Contextimport android.support.v7.widget.RecyclerViewimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.TextViewimport com.allrun.dangjianshisanshi.Rimport com.allrun.dangjianshisanshi.actvity.schedule.ScheduleActivityimport com.allrun.dangjianshisanshi.ardangjianshisanshi.entity.entity_base_obj_objlistimport com.allrun.dangjianshisanshi.ardangjianshisanshi.entity.entity_null_objimport com.allrun.dangjianshisanshi.ardangjianshisanshi.entity.scheduleObjimport com.allrun.dangjianshisanshi.model.ModelHolderimport com.allrun.dangjianshisanshi.util.LunarCalendarimport com.allrun.dangjianshisanshi.widget.PPBallimport org.jetbrains.anko.backgroundDrawableimport java.text.SimpleDateFormatimport java.util.*/** * Created by greendami on 2017/8/24. */class DateNavigateAdapter(var context: Context, var c: Calendar, var modelHolder: ModelHolder) : RecyclerView.Adapter() { var emptyCount = 0 var today = Date() var sdf = SimpleDateFormat("yyyyMMdd") override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.date_navigate_item, parent, false) return MyViewHolder(view) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { initNormal(holder, position) } private fun initNormal(holder: RecyclerView.ViewHolder, position: Int) { var myHolder: MyViewHolder = holder as MyViewHolder if (position < emptyCount) { myHolder.tv.visibility = View.GONE } else { myHolder.tv.text = "${position + 1 - emptyCount}" c.set(Calendar.DATE, position + 1 - emptyCount) myHolder.tv2.text = LunarCalendar().getLunarDate(c.get(Calendar.YEAR),c.get(Calendar.MONTH)+1,c.get(Calendar.DAY_OF_MONTH),false) var dateString = sdf.format(c.time) //周日周六的颜色浅 if(position%7 == 0 ||position%7 == 6){ myHolder.tv.setTextColor(context.resources.getColor(R.color.text_color4)) } //显示今天 if(sdf.format(today) == dateString){ myHolder.ll_tv.backgroundDrawable = context.resources.getDrawable(R.drawable.red_circle3) myHolder.tv.setTextColor(context.resources.getColor(R.color.text_color2)) myHolder.tv2.setTextColor(context.resources.getColor(R.color.text_color4)) } //选中 if(modelHolder.get >().value?.obj?.s != null &&modelHolder.get >().value!!.obj.s == dateString){ myHolder.ll_tv.backgroundDrawable = context.resources.getDrawable(R.drawable.red_circle2) myHolder.tv.setTextColor(context.resources.getColor(R.color.white)) myHolder.tv2.setTextColor(context.resources.getColor(R.color.white)) } //显示点点 myHolder.point.visibility = View.GONE modelHolder.get >().value?.objList?.forEach { if(it.replace("-","") == dateString){ myHolder.point.visibility = View.VISIBLE return@forEach } } myHolder.ll_tv.setOnClickListener { context as ScheduleActivity c.set(Calendar.DATE, position + 1 - emptyCount) modelHolder.get >().value!!.obj = entity_null_obj(dateString) modelHolder.callUpdate() } } } override fun getItemViewType(position: Int): Int { return position } //获得当月天数,并加上前面的空白天数 override fun getItemCount(): Int { c.set(Calendar.DATE, 1)//把日期设置为当月第一天 emptyCount = c.get(Calendar.DAY_OF_WEEK) - 1//第一天是星期几,前面要空出来 c.roll(Calendar.DATE, -1)//日期回滚一天,也就是最后一天 val maxDate = c.get(Calendar.DATE) return maxDate + emptyCount } internal inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var tv: TextView = itemView.findViewById(R.id.tv) var tv2: TextView = itemView.findViewById(R.id.tv2) var ll_tv: View = itemView.findViewById(R.id.ll_tv) var point = itemView.findViewById (R.id.point) }}复制代码
其实有的月份的第一天可能不是星期日,所以开始可能有几天是空白的,如下图:
2017年9月1日就是星期五,前面就空出来了几天,这几天的数量需要算进来,然后在getItemCount()中加上。这里代码上有注释。然后在onBindViewHolder()的时候,把空白几天的Item隐藏。
if (position < emptyCount) { myHolder.tv.visibility = View.GONE}复制代码
这里使用View.GONE并不会让后面的item把前面的Item的位置顶掉。因为整个数据集的数量我们已经给定了。这里是数量决定的。
如果只是显示日期:myHolder.tv.text = "${position + 1 - emptyCount}" 这样就可以通过Position和前面的空白Item的数量直接算出。
下面是显示农历,具体农历的算出,我是在网上找的代码:package com.greendami.util;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Calendar;import java.util.Date;/** * Created by greendami on 2017/10/13. */public class LunarCalendar { private int year; // 农历的年份 private int month; private int day; private String lunarMonth; // 农历的月份 private boolean leap; public int leapMonth = 0; // 闰的是哪个月 final static String chineseNumber[] = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" }; static SimpleDateFormat chineseDateFormat = new SimpleDateFormat( "yyyy年MM月dd日"); final static long[] lunarInfo = new long[] { 0x4bd8, 0x4ae0, 0xa570, 0x54d5, 0xd260, 0xd950, 0x5554, 0x56af, 0x9ad0, 0x55d2, 0x4ae0, 0xa5b6, 0xa4d0, 0xd250, 0xd255, 0xb54f, 0xd6a0, 0xada2, 0x95b0, 0x4977, 0x497f, 0xa4b0, 0xb4b5, 0x6a50, 0x6d40, 0xab54, 0x2b6f, 0x9570, 0x52f2, 0x4970, 0x6566, 0xd4a0, 0xea50, 0x6a95, 0x5adf, 0x2b60, 0x86e3, 0x92ef, 0xc8d7, 0xc95f, 0xd4a0, 0xd8a6, 0xb55f, 0x56a0, 0xa5b4, 0x25df, 0x92d0, 0xd2b2, 0xa950, 0xb557, 0x6ca0, 0xb550, 0x5355, 0x4daf, 0xa5b0, 0x4573, 0x52bf, 0xa9a8, 0xe950, 0x6aa0, 0xaea6, 0xab50, 0x4b60, 0xaae4, 0xa570, 0x5260, 0xf263, 0xd950, 0x5b57, 0x56a0, 0x96d0, 0x4dd5, 0x4ad0, 0xa4d0, 0xd4d4, 0xd250, 0xd558, 0xb540, 0xb6a0, 0x95a6, 0x95bf, 0x49b0, 0xa974, 0xa4b0, 0xb27a, 0x6a50, 0x6d40, 0xaf46, 0xab60, 0x9570, 0x4af5, 0x4970, 0x64b0, 0x74a3, 0xea50, 0x6b58, 0x5ac0, 0xab60, 0x96d5, 0x92e0, 0xc960, 0xd954, 0xd4a0, 0xda50, 0x7552, 0x56a0, 0xabb7, 0x25d0, 0x92d0, 0xcab5, 0xa950, 0xb4a0, 0xbaa4, 0xad50, 0x55d9, 0x4ba0, 0xa5b0, 0x5176, 0x52bf, 0xa930, 0x7954, 0x6aa0, 0xad50, 0x5b52, 0x4b60, 0xa6e6, 0xa4e0, 0xd260, 0xea65, 0xd530, 0x5aa0, 0x76a3, 0x96d0, 0x4afb, 0x4ad0, 0xa4d0, 0xd0b6, 0xd25f, 0xd520, 0xdd45, 0xb5a0, 0x56d0, 0x55b2, 0x49b0, 0xa577, 0xa4b0, 0xaa50, 0xb255, 0x6d2f, 0xada0, 0x4b63, 0x937f, 0x49f8, 0x4970, 0x64b0, 0x68a6, 0xea5f, 0x6b20, 0xa6c4, 0xaaef, 0x92e0, 0xd2e3, 0xc960, 0xd557, 0xd4a0, 0xda50, 0x5d55, 0x56a0, 0xa6d0, 0x55d4, 0x52d0, 0xa9b8, 0xa950, 0xb4a0, 0xb6a6, 0xad50, 0x55a0, 0xaba4, 0xa5b0, 0x52b0, 0xb273, 0x6930, 0x7337, 0x6aa0, 0xad50, 0x4b55, 0x4b6f, 0xa570, 0x54e4, 0xd260, 0xe968, 0xd520, 0xdaa0, 0x6aa6, 0x56df, 0x4ae0, 0xa9d4, 0xa4d0, 0xd150, 0xf252, 0xd520}; // 农历部分假日 final static String[] lunarHoliday = new String[] { "0101 春节", "0115 元宵", "0505 端午", "0707 七夕", "0715 中元", "0730 地藏",// "0802 灶君诞", "0815 中秋",// "0827 先师诞", "0909 重阳", "1208 腊八", "1223 小年", "0100 除夕" }; // 公历部分节假日 final static String[] solarHoliday = new String[] { "0101 元旦",// "0110 中国110宣传日", "0214 情人",// "0221 国际母语日",// "0303 国际爱耳日", "0308 妇女", "0312 植树",// "0315 消费者权益日",// "0322 世界水日",// "0323 世界气象日", "0401 愚人",// "0407 世界卫生日", "0501 劳动", "0504 青年", "0512 护士",// "0519 全国助残日",// "0531 世界无烟日", "0601 儿童",// "0626 国际禁毒日", "0701 建党", //1921 "0801 建军", //1933 //"0808 父亲节",// "0909 毛泽东逝世纪念", //1976 "0910 教师",// "0917 国际和平日",// "0927 世界旅游日",// "0928 孔子诞辰", "1001 国庆",// "1006 老人节",// "1007 国际住房日",// "1014 世界标准日",// "1024 联合国日",// "1112 孙中山诞辰纪念",// "1210 世界人权日",// "1220 澳门回归纪念", "1224 平安", "1225 圣诞"// "1226 毛泽东诞辰纪念" }; //24节气 final static String[] sTermInfo = new String[]{ // 时节 气候 "小寒","大寒", "立春","雨水", "惊蛰","春分", "清明","谷雨", "立夏","小满", "芒种","夏至", "小暑","大暑", "立秋","处暑", "白露","秋分", "寒露","霜降", "立冬","小雪", "大雪","冬至" }; final static String[] constellations = new String[]{ "摩蝎座:12.22—01.19","水瓶座:01.20—02.18","双鱼座:02.19—03.20","白羊座:03.21—04.19", "金牛座:04.20—05.20","双子座:05.21—06.20","巨蟹座:06.21—07.21","狮子座:07.22—08.22", "处女座:08.23—09.22","天秤座:09.23—10.22","天蝎座:10.23—11.21","射手座:11.22—12.21" }; final static String[] yi_string = new String[]{ "出行.上任.会友.上书.见工","除服.疗病.出行.拆卸.入宅", "祈福.祭祀.结亲.开市.交易","祭祀.修填.涂泥.余事勿取", "交易.立券.会友.签约.纳畜","祈福.祭祀.求子.结婚.立约", "求医.赴考.祭祀.余事勿取","经营.交易.求官.纳畜.动土", "祈福.入学.开市.求医.成服","祭祀.求财.签约.嫁娶.订盟", "疗病.结婚.交易.入仓.求职","祭祀.交易.收财.安葬" }; final static String[] ji_string = new String[]{ "动土.开仓.嫁娶.纳采","求官.上任.开张.搬家.探病", "服药.求医.栽种.动土.迁移","移徙.入宅.嫁娶.开市.安葬", "种植.置业.卖田.掘井.造船","开市.交易.搬家.远行", "动土.出行.移徙.开市.修造","登高.行船.安床.入宅.博彩", "词讼.安门.移徙","开市.安床.安葬.入宅.破土", "安葬.动土.针灸","宴会.安床.出行.嫁娶.移徙" }; final static String[][] jcName = new String[][]{ { "建","除","满","平","定","执","破","危","成","收","开","闭"}, { "闭","建","除","满","平","定","执","破","危","成","收","开"}, { "开","闭","建","除","满","平","定","执","破","危","成","收"}, { "收","开","闭","建","除","满","平","定","执","破","危","成"}, { "成","收","开","闭","建","除","满","平","定","执","破","危"}, { "危","成","收","开","闭","建","除","满","平","定","执","破"}, { "破","危","成","收","开","闭","建","除","满","平","定","执"}, { "执","破","危","成","收","开","闭","建","除","满","平","定"}, { "定","执","破","危","成","收","开","闭","建","除","满","平"}, { "平","定","执","破","危","成","收","开","闭","建","除","满"}, { "满","平","定","执","破","危","成","收","开","闭","建","除"}, { "除","满","平","定","执","破","危","成","收","开","闭","建"} }; final static String[] Gan = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" }; final static String[] Zhi = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" }; // ====== 传回农历 y年的总天数 1900--2100 public int yearDays(int y) { int i, sum = 348; for (i = 0x8000; i > 0x8; i >>= 1) { if ((lunarInfo[y - 1900] & i) != 0) sum += 1; } return (sum + leapDays(y)); } // ====== 传回农历 y年闰月的天数 public int leapDays(int y) { if (leapMonth(y) != 0) { if ((lunarInfo[y - 1899] & 0xf) != 0) return 30; else return 29; } else return 0; } // ====== 传回农历 y年闰哪个月 1-12 , 没闰传回 0 public int leapMonth(int y) { long var = lunarInfo[y - 1900] & 0xf; return (int)(var == 0xf ? 0 : var); } // ====== 传回农历 y年m月的总天数 public int monthDays(int y, int m) { if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0) return 29; else return 30; } // ====== 传回农历 y年的生肖 public String animalsYear(int year) { final String[] Animals = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" }; return Animals[(year - 4) % 12]+"年"; } // ====== 传入 月日的offset 传回干支, 0=甲子 final private static String cyclicalm(int num) { return (Gan[num % 10] + Zhi[num % 12]); } // ====== 传入 offset 传回干支, 0=甲子 final public String cyclical(int year, int month,int day) { int num = year - 1900 + 36; //立春日期 int term2 = sTerm(year, 2); if(month>2 || (month==2 && day>= term2)){ num = num + 0; }else{ num = num -1; } return (cyclicalm(num)); } public static String getChinaDayString(int day) { //将农历day日格式化成农历表示的字符串 String chineseTen[] = { "初", "十", "廿", "卅" }; String chineseDay[] = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}; String var=""; if(day!=20 && day != 30){ var = chineseTen[(int)((day-1)/10)]+ chineseDay[(int)((day-1)%10)]; }else if(day !=20){ var = chineseTen[(int)(day/10)]+"十"; }else{ var = "二十"; } return var; } /* * 计算公历nY年nM月nD日和bY年bM月bD日渐相差多少天 * */ public int getDaysOfTwoDate(int bY,int bM, int bD,int nY, int nM,int nD){ Date baseDate = null; Date nowaday = null; try { baseDate = chineseDateFormat.parse(bY+"年"+bM+"月"+bD+"日"); nowaday = chineseDateFormat.parse(nY+"年"+nM+"月"+nD+"日"); } catch (ParseException e) { e.printStackTrace(); } // 求出相差的天数 int offset = (int) ((nowaday.getTime() - baseDate.getTime()) / 86400000L); return offset; } /*农历lunYear年lunMonth月lunDay日 * isLeap 当前年月是否是闰月 * 从农历日期转换成公历日期 * */ public Calendar getSunDate(int lunYear, int lunMonth, int lunDay, boolean isLeap){ //公历1900年1月31日为1900年正月初一 int years = lunYear -1900; int days=0; for(int i=0;ileapMonth(lunYear)){ days += leapDays(lunYear);//lunYear年闰月天数 } if(isLeap){ days +=monthDays(lunYear,lunMonth);//lunYear年lunMonth月 闰月 } days +=lunDay; days = days-1; Calendar cal=Calendar.getInstance(); cal.set(Calendar.YEAR, 1900); cal.set(Calendar.MONTH, 0); cal.set(Calendar.DAY_OF_MONTH,31); cal.add(Calendar.DATE, days); /* Date date=cal.getTime(); int year_c = cal.get(Calendar.YEAR); int month_c = cal.get(Calendar.MONTH)+1; int day_c = cal.get(Calendar.DAY_OF_MONTH); */ return cal; } public String getLunarString(int year, int month, int day){ int var = getLunarDateINT(year,month,day); int lYear = (int)var/10000; int lMonth = (int)(var%10000)/100; int lDay = var - lYear*10000 - lMonth*100; String lunY = cyclical(year,month,day)+"年"; String lunM=""; int testMonth = getSunDate(lYear,lMonth,lDay,false).get(Calendar.MONTH)+1; if(testMonth!=month){ lunM = "闰"; } lunM += chineseNumber[(lMonth-1)%12]+"月"; //int leap = leapMonth(lYear); String lunD = getChinaDayString(lDay); int animalsYear = 0; int term2 = sTerm(year, 2);//立春 if(month>2 ||(month==2&& day>=term2)){ animalsYear = year; }else{ animalsYear = year-1; } String Festival = getFestival(year,month,day); //return lunY+"-"+lunM+"-"+lunD+"-"+animalsYear(animalsYear); return "农历 "+lunM+lunD+" "+Festival; } /* * 将公历year年month月day日转换成农历 * 返回格式为20140506(int) * */ public int getLunarDateINT(int year, int month, int day){ int iYear,LYear,LMonth,LDay, daysOfYear = 0; // 求出和1900年1月31日相差的天数 //year =1908; //month = 3; //day =3; int offset = getDaysOfTwoDate(1900,1,31,year,month,day); //Log.i("--ss--","公历:"+year+"-"+month+"-"+day+":"+offset); // 用offset减去每农历年的天数 // 计算当天是农历第几天 // i最终结果是农历的年份 // offset是当年的第几天 for (iYear = 1900; iYear < 2100 && offset >0; iYear++) { daysOfYear = yearDays(iYear); offset -= daysOfYear; //Log.i("--ss--","农历:"+iYear+":"+daysOfYear+"/"+offset); } if (offset < 0) { offset += daysOfYear; iYear--; //Log.i("--ss--","农历:"+iYear+":"+daysOfYear+"/"+offset); } // 农历年份 LYear = iYear; leapMonth = leapMonth(iYear); // 闰哪个月,1-12 leap = false; // 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天 int iMonth=1, daysOfMonth = 0; for (iMonth = 1; iMonth < 13 && offset >0; iMonth++) { // 闰月 if (leapMonth > 0 && iMonth == (leapMonth + 1) && !leap) { --iMonth; leap = true; daysOfMonth = leapDays(iYear); } else{ daysOfMonth = monthDays(iYear, iMonth); } // 解除闰月 if (leap && iMonth == (leapMonth + 1)) leap = false; offset -= daysOfMonth; //Log.i("--ss--","农历:"+iYear+"-"+iMonth+":"+daysOfMonth+"/"+offset); } // offset为0时,并且刚才计算的月份是闰月,要校正 if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) { if (leap) { leap = false; } else { leap = true; --iMonth; } } // offset小于0时,也要校正 if (offset < 0) { offset += daysOfMonth; --iMonth; //Log.i("--ss--","农历:"+iYear+"-"+iMonth+":"+daysOfMonth+"/"+offset); } LMonth = iMonth; LDay = offset + 1; //Log.i("--ss--","农历:"+LYear+"-"+LMonth+"-"+LDay); return LYear * 10000 + LMonth *100 + LDay; } public String getFestival(int year, int month, int day){ //获取公历对应的节假日或二十四节气 //农历节假日 int var = getLunarDateINT(year, month, day); int lun_year = (int)var/10000; int lun_month = (int)(var%10000)/100; int lun_Day = (int)(var - lun_year*10000 - lun_month*100); for (int i = 0; i < lunarHoliday.length; i++) { // 返回农历节假日名称 String ld = lunarHoliday[i].split(" ")[0]; // 节假日的日期 String ldv = lunarHoliday[i].split(" ")[1]; // 节假日的名称 String lmonth_v = lun_month + ""; String lday_v = lun_Day + ""; String lmd = ""; if (month < 10) { lmonth_v = "0" + lun_month; } if (day < 10) { lday_v = "0" + lun_Day; } lmd = lmonth_v + lday_v; if (ld.trim().equals(lmd.trim())) { return ldv; } } //公历节假日 for (int i = 0; i < solarHoliday.length; i++) { if(i==solarHoliday.length && year<1893 //1893年前没有此节日 || i+3 == solarHoliday.length && year<1999 || i+6 == solarHoliday.length && year<1942 || i+10 == solarHoliday.length && year<1949 || i == 19 && year<1921 || i == 20 && year<1933 || i == 22 && year<1976){ break; } // 返回公历节假日名称 String sd = solarHoliday[i].split(" ")[0]; // 节假日的日期 String sdv = solarHoliday[i].split(" ")[1]; // 节假日的名称 String smonth_v = month + ""; String sday_v = day + ""; String smd = ""; if (month < 10) { smonth_v = "0" + month; } if (day < 10) { sday_v = "0" + day; } smd = smonth_v + sday_v; if (sd.trim().equals(smd.trim())) { return sdv; } } int b = getDateOfSolarTerms(year,month); if(day==(int)b/100){ return sTermInfo[(month-1)*2]; }else if(day== b%100){ return sTermInfo[(month-1)*2+1]; } return ""; } /** */ /** * 传出y年m月d日对应的农历. yearCyl3:农历年与1864的相差数 ? monCyl4:从1900年1月31日以来,闰月数 * dayCyl5:与1900年1月31日相差的天数,再加40 ? * * isday: 这个参数为false---日期为节假日时,阴历日期就返回节假日 ,true---不管日期是否为节假日依然返回这天对应的阴历日期 * * @return */ public String getLunarDate(int year_log, int month_log, int day_log, boolean isday) { int var = getLunarDateINT(year_log,month_log,day_log); // 农历年份 year = (int)var/10000; setYear(year); // 设置公历对应的农历年份 //农历月份 month = (int)Math.ceil((var%10000)/100); setLunarMonth(chineseNumber[(month-1)%12] + "月"); // 设置对应的阴历月份 day = var - year*10000 - month*100; if (!isday) { String Festival = getFestival(year_log,month_log,day_log); if(Festival.length()>1){ return Festival; } } if (day == 1) return chineseNumber[(month-1)%12] + "月"; else return getChinaDayString(day); } public String toString() { if (chineseNumber[(month-1)%12] == "正" && getChinaDayString(day) == "初一") return "农历" + year + "年"; else if (getChinaDayString(day) == "初一") return chineseNumber[(month-1)%12] + "月"; else return getChinaDayString(day); // return year + "年" + (leap ? "闰" : "") + chineseNumber[month - 1] + // "月" + getChinaDayString(day); } /* * public static void main(String[] args) { System.out.println(new * LunarCalendar().getLunarDate(2012, 1, 23)); } */ public int getLeapMonth() { return leapMonth; } public void setLeapMonth(int leapMonth) { this.leapMonth = leapMonth; } /** * 得到当前日期对应的阴历月份 * * @return */ public String getLunarMonth() { return lunarMonth; } public void setLunarMonth(String lunarMonth) { this.lunarMonth = lunarMonth; } /** * 得到当前年对应的农历年份 * * @return */ public int getYear() { return year; } public void setYear(int year) { this.year = year; } public String getConstellation(int month, int day){ //计算星座 int date = month*100 + day; String constellation=""; if(date>=120 && date <=218){ constellation = constellations[1]; }else if(date>=219 && date<=320){ constellation = constellations[2]; }else if(date>=321 && date<=419){ constellation = constellations[3]; }else if(date>=420 && date<=520){ constellation = constellations[4]; }else if(date>=521 && date<=620){ constellation = constellations[5]; }else if(date>=621 && date<=721){ constellation = constellations[6]; }else if(date>=722 && date<=822){ constellation = constellations[7]; }else if(date>=823 && date<=922){ constellation = constellations[8]; }else if(date>=923 && date<=1022){ constellation = constellations[9]; }else if(date>=1023 && date<=1121){ constellation = constellations[10]; }else if(date>=1122 && date<=1221){ constellation = constellations[11]; }else{ constellation = constellations[0]; } return constellation; } private int sTerm(int y, int n) { int[] sTermInfo = new int[]{ 0,21208,42467,63836,85337,107014, 128867,150921,173149,195551,218072,240693, 263343,285989,308563,331033,353350,375494, 397447,419210,440795,462224,483532,504758}; Calendar cal = Calendar.getInstance(); cal.set(1900, 0, 6, 2, 5, 0); long temp = cal.getTime().getTime(); cal.setTime(new Date( (long) ((31556925974.7 * (y - 1900) + sTermInfo[n] * 60000L) + temp))); int a=cal.get(Calendar.DAY_OF_MONTH); return a; } public int getDateOfSolarTerms(int year, int month){ int a = sTerm(year,(month-1)*2); int b = sTerm(year,(month-1)*2 +1); return a*100+b; //return 0; } public String jcrt(String d) { String jcrjxt=""; String yj0 = "宜:\t",yj1 = "忌:\t",br = "-"; //String yj0 = "",yj1 = "",br = "-"; if (d == "建") jcrjxt = yj0 + yi_string[0] + br + yj1 + ji_string[0]; if (d == "除") jcrjxt = yj0 + yi_string[1] + br + yj1 + ji_string[1]; if (d == "满") jcrjxt = yj0 + yi_string[2] + br + yj1 + ji_string[2]; if (d == "平") jcrjxt = yj0 + yi_string[3] + br + yj1 + ji_string[3]; if (d == "定") jcrjxt = yj0 + yi_string[4] + br + yj1 + ji_string[4]; if (d == "执") jcrjxt = yj0 + yi_string[5] + br + yj1 + ji_string[5]; if (d == "破") jcrjxt = yj0 + yi_string[6] + br + yj1 + ji_string[6]; if (d == "危") jcrjxt = yj0 + yi_string[7] + br + yj1 + ji_string[7]; if (d == "成") jcrjxt = yj0 + yi_string[8] + br + yj1 + ji_string[8]; if (d == "收") jcrjxt = yj0 + yi_string[9] + br + yj1 + ji_string[9]; if (d == "开") jcrjxt = yj0 + yi_string[10] + br + yj1 + ji_string[10]; if (d == "闭") jcrjxt = yj0 + yi_string[11] + br + yj1 + ji_string[11]; return jcrjxt; } /* num_y%12, num_m%12, num_d%12, num_y%10, num_d%10 * m:农历月份 1---12 * dt:农历日 * */ public String CalConv2(int yy, int mm, int dd, int y, int d, int m, int dt) { String dy = d + "" + dd; if ((yy == 0 && dd == 6) || (yy == 6 && dd == 0) || (yy == 1 && dd == 7) || (yy == 7 && dd == 1) || (yy == 2 && dd == 8) || (yy == 8 && dd == 2) || (yy == 3 && dd == 9) || (yy == 9 && dd == 3) || (yy == 4 && dd == 10) || (yy == 10 && dd == 4) || (yy == 5 && dd == 11) || (yy == 11 && dd == 5)) { /* * 地支共有六对相冲,俗称“六冲”,即:子午相冲、丑未相冲、寅申相冲、卯酉相冲、辰戌相冲、巳亥相冲。 * 如当年是甲子年,子为太岁,与子相冲者是午,假如当日是午日,则为岁破,其余的以此类推,即丑年的岁破为未日, * 寅年的岁破为申日,卯年的岁破为酉日,辰年的岁破为戌日,巳年的岁破为亥日,午年的岁破为子日,未年的岁破为丑日, * 申年的岁破为寅日,酉年的岁破为卯日,戌年的岁破为辰日,亥年的岁破为巳日。 * */ return "日值岁破 大事不宜"; } else if ((mm == 0 && dd == 6) || (mm == 6 && dd == 0) || (mm == 1 && dd == 7) || (mm == 7 && dd == 1) || (mm == 2 && dd == 8) || (mm == 8 && dd == 2) || (mm == 3 && dd == 9) || (mm == 9 && dd == 3) || (mm == 4 && dd == 10) || (mm == 10 && dd == 4) || (mm == 5 && dd == 11) || (mm == 11 && dd == 5)) { return "日值月破 大事不宜"; } else if ((y == 0 && dy == "911") || (y == 1 && dy == "55") || (y == 2 && dy == "111") || (y == 3 && dy == "75") || (y == 4 && dy == "311") || (y == 5 && dy == "95") || (y == 6 && dy == "511")|| (y == 7 && dy == "15") || (y == 8 && dy == "711") || (y == 9 && dy == "35")) { return "日值上朔 大事不宜"; } else if ((m == 1 && dt == 13) || (m == 2 && dt == 11) || (m == 3 && dt == 9) || (m == 4 && dt == 7) || (m == 5 && dt == 5) || (m == 6 && dt == 3) || (m == 7 && dt == 1) || (m == 7 && dt == 29) || (m == 8 && dt == 27) || (m == 9 && dt == 25) || (m == 10 && dt == 23) || (m == 11 && dt == 21) || (m == 12 && dt == 19)) { /* * 杨公十三忌 以农历正月十三日始,以后每月提前两天为百事禁忌日 * */ return "日值杨公十三忌 大事不宜"; //}else if(var == getSiLi(m,dt)){ //return "日值四离 大事勿用"; } else { return null; } } public int getDaysOfMonth(int year, int month){ //返回公历year年month月的当月总天数 if(month == 2){ return(((year%4 == 0) && (year%100 != 0) || (year%400 == 0))? 29: 28); }else if(month == 1 || month == 3 ||month == 5 || month == 7 || month == 8 ||month == 10 || month == 12){ return 31; } return 30; } /*输入 * year 公历年份,大于1900 * month 公历月份 1--12 * 输出 * ArrayList year年month月全月宜忌 * */ public ArrayList getyiji(int year, int month) { int num_y = -1; int num_m = (year - 1900) * 12 + month-1 +12; int num_d; int mLMonth=1,mLDay=1,mLun_x=0; int days_of_month = getDaysOfMonth(year, month); ArrayList yiji = new ArrayList (); //年柱 1900年立春后为庚子年(60进制36) //cyclical(year,month); //立春日期 int term2 = sTerm(year, 2); //月柱 1900年1月小寒以前为 丙子月(60进制12) int firstNode = sTerm(year, (month-1)*2);//当月的24节气中的节开始日 //cyclicalm(num_m); //Calendar cal = Calendar.getInstance(); //cal.set(year, month, 1, 0, 0, 0); //1900/1/1与 1970/1/1 相差25567日, 1900/1/1 日柱为甲戌日(60进制10) int dayCyclical = (int) (getDaysOfTwoDate(1900,1,1,year,month,1)+10); for(int i=0;i mLun_x){ //Log.i("","mLDay > mLun_x "+mLDay+":"+mLun_x); int var = getLunarDateINT(year,month,i+1); int mLYear =(int)var/10000; mLMonth = (int)(var%10000)/100; mLDay = (int)(var - mLYear*10000 - mLMonth*100); mLun_x = (leapMonth(mLYear)!=0)?leapDays(mLYear):monthDays(mLYear, mLMonth); //Log.i("","mLDay > mLun_x ?"+mLDay+":"+mLun_x); } //依节气调整二月分的年柱, 以立春为界 if(month==2 && (i+1)==term2){ //cY = cyclicalm(year-1900 + 36); num_y = year - 1900 + 36; } //依节气 调整月柱, 以「节」为界 if((i+1)==firstNode) { num_m =(year - 1900) * 12 + month +12 ; //cM = cyclicalm(num_m); } //日柱 //cD = cyclicalm(dayCyclical + i); num_d = dayCyclical +i; mLDay++; //Log.i("","---num_y:"+num_y+","+num_m+","+num_d+",n_m:"+mLMonth+",n_d:"+mLDay+",mLun_x:"+mLun_x); String str = CalConv2(num_y%12, num_m%12, num_d%12, num_y%10, num_d%10, mLMonth, mLDay-1); if(str == null){ String var = jcName[num_m%12][num_d%12]; str = jcrt(var); //Log.i("","---"+month+"-"+(i+1)+","+var+":"+str); } //Log.i("","---"+year+"-"+month+"-"+(i+1)+","+str); yiji.add(str); } return yiji; } /* * 公历某日宜忌 * */ public String getyiji(int year, int month, int day) { int num_y = -1; int num_m = (year - 1900) * 12 + month-1 +12; int num_d; int mLMonth=1,mLDay=1; int days_of_month = getDaysOfMonth(year, month); if(day > days_of_month) day = days_of_month; //年柱 1900年立春后为庚子年(60进制36) //cyclical(year,month); //立春日期 int term2 = sTerm(year, 2); int firstNode = sTerm(year, (month-1)*2);//当月的24节气中的节开始日 int dayCyclical = (int) (getDaysOfTwoDate(1900,1,1,year,month,1)+10); if(month==2 && day==term2){ //cY = cyclicalm(year-1900 + 36);//依节气调整二月分的年柱, 以立春为界 num_y = year - 1900 + 36; } if(day==firstNode) { num_m =(year - 1900) * 12 + month +12 ;//依节气 调整月柱, 以「节」为界 //cM = cyclicalm(num_m); } num_d = dayCyclical +day -1; int var = getLunarDateINT(year,month,day); int mLYear =(int)var/10000; mLMonth = (int)(var%10000)/100; mLDay = (int)(var - mLYear*10000 - mLMonth*100); //Log.i("","---num_y:"+num_y+","+num_m+","+num_d+",n_m:"+mLMonth+",n_d:"+mLDay+",mLun_x:"+mLun_x); String str = CalConv2(num_y%12, num_m%12, num_d%12, num_y%10, num_d%10, mLMonth, mLDay); if(str == null){ str = jcrt(jcName[num_m%12][num_d%12]); //Log.i("","---"+month+"-"+(i+1)+","+var+":"+str); } //Log.i("","---"+year+"-"+month+"-"+(i+1)+","+str); return str; } /* * 计算距离1900年12月31日days天后的日期 * */ public int getDateFromBaseDate(int days){ int year = 0,month = 0,day = 0; Calendar cal=Calendar.getInstance(); cal.set(Calendar.YEAR, 1900); cal.set(Calendar.MONTH, 0); cal.set(Calendar.DAY_OF_MONTH,31); cal.add(Calendar.DATE, days); year = cal.get(Calendar.YEAR); month = cal.get(Calendar.MONTH)+1; day = cal.get(Calendar.DAY_OF_MONTH); return 10000*year+100*month+day; }}复制代码
在getLunarDate方法中我修改了一下,原来的月份计算有点问题,没有向上取整month = (int)Math.ceil((var%10000)/100);这是我修改的。
请注意,在调用的时候myHolder.tv2.text = LunarCalendar().getLunarDate(c.get(Calendar.YEAR),c.get(Calendar.MONTH)+1,c.get(Calendar.DAY_OF_MONTH),false)复制代码
月份 加了1。Calendar的月份是从0开始的。
然后说说点击选中效果:
点击的时候myHolder.ll_tv.setOnClickListener { context as ScheduleActivity c.set(Calendar.DATE, position + 1 - emptyCount) modelHolder.get>().value!!.obj = entity_null_obj(dateString) modelHolder.callUpdate() }复制代码
我把点击的日期放在了modelHolder中,然后通知modelHolder刷新,modelHolder就会在外部刷新adapter,然后modelHolder.get>().value?.obj?.s就是我们点击的日期,就被带到adapter里面了。
//选中if(modelHolder.get>().value?.obj?.s != null &&modelHolder.get >().value!!.obj.s == dateString){ myHolder.ll_tv.backgroundDrawable = context.resources.getDrawable(R.drawable.red_circle2) myHolder.tv.setTextColor(context.resources.getColor(R.color.white)) myHolder.tv2.setTextColor(context.resources.getColor(R.color.white))}复制代码
这里就是显示被选中的式样。这样处理在切换月份后,选中日期不会丢失,在切换回之前的月份后,选中的日期还是选中的式样。
选中日期的事件处理,比如请求网络数据,我写在了modelHolder刷新Adapter的时候,在那里modelHolder会收到选中的日期。
modelHolder.get>().observe(this, android.arch.lifecycle.Observer { //收到事件,进行处理})复制代码
点击月份的前后箭头,可以切换月份
before_bt.setOnClickListener { c?.add(Calendar.MONTH, -1) date_text.text = sdf.format(c?.time) loadData() }next_bt.setOnClickListener { c?.add(Calendar.MONTH, 1) date_text.text = sdf.format(c?.time) loadData() }复制代码
切换月份后,重新加载adapter即可。
最后,附赠一个收起控件的操作,手指按住下面的那两条横线,向上移动,控件会跟随手指移动,最终关闭。ll_toggle.setOnClickListener { ll_show_date.visibility = View.GONE } ll_toggle.setOnTouchListener { view, event -> if (event.action == MotionEvent.ACTION_DOWN && downY == 0f) { downY = (ll_show_date.parent as ViewGroup).y } if (event.action == MotionEvent.ACTION_MOVE) { if (-ll_show_date.height + event.rawY > downY || event.rawY <= downY) { //限制滑动范围 true } else { (ll_show_date.parent as ViewGroup).y = -ll_show_date.height + event.rawY //移动过程中,隐藏下面的列表 list.visibility = View.INVISIBLE } } if (event.action == MotionEvent.ACTION_UP) { if (-ll_show_date.height + event.rawY < downY) { (ll_show_date.parent as ViewGroup).y = downY ll_show_date.visibility = View.GONE } //移动完了,显示列表 list.visibility = View.VISIBLE } false }复制代码
这部分代码没什么营养,就是根据手指坐标,修改控件的坐标。
最后的最后,ModelHolder是Livedata中的ViewModel。