周日历

地址: https://github.com/LineChen/Week_Calendar

实现

WeekCalendar是一个继承LinearLayout的ViewGroup,而不是一个View,显示方式完全由使用者控制,类似ListView使用。

关于布局: WeekCalendar是继承自LinearLayout,内部主要有两个直接子控件,星期Layout和日期Layout。星期Layout是一个GridView,日期Layout是一个固定高度的ViewPager。为了让使用者有可以无限滑动的感觉,这里的ViewPager需要做成“无限”的。每一个周布局是一个GridView。

无限ViewPager:

并不是真的无限。实现是在PagerAdapter的getCount()中返回一个较大的数,这里返回的是1000,然后调用ViewPager的setCurrentItem(int)设置为最大值的一半。当然仅仅这样还是不够的。 Jackwharton借鉴了一下ListView的缓存模式,并使用在ViewPager中,所以再添加一个缓存基本就完成了。

缓存中最重要的一个类是RecycleBin,是直接从官方代码中拿出来的。RecycleBin的官方解释是:RecycleBin有助于在布局之间重用视图。 RecycleBin有两个级别的存储:ActiveViews和ScrapViews。 ActiveView是在布局开始时在屏幕上的那些视图。 通过构造行数,他们正在显示当前的信息。 在布局结束时,ActiveView中的所有视图都将降级为ScrapViews。 ScrapViews是可能被适配器使用的旧视图,以避免不必要地分配视图。

结合PagerAdapter就可以让ViewPager使用缓存了:

重写一个RecyclingPagerAdapter继承PagerAdapter,在instantiateItem和destroyItem使用缓存,详细信息请看源码

@Overridepublic final Object instantiateItem(ViewGroup container, int position) {int viewType = getItemViewType(position);View view = null;if (viewType != IGNORE_ITEM_VIEW_TYPE) {//先从缓存中获取视图view = recycleBin.getScrapView(position, viewType);}view = getView(position, view, container);container.addView(view);return view;}
@Overridepublic final void destroyItem(ViewGroup container, int position, Object object) {View view = (View) object;container.removeView(view);int viewType = getItemViewType(position);if (viewType != IGNORE_ITEM_VIEW_TYPE) {//在这里将视图缓存recycleBin.addScrapView(view, position, viewType);}}

使用缓存后,只有在开始的时候创建了三个新的视图。

接下来就是显示了~

为了让使用者控制显示布局,定义了一个接口。

public interface GetViewHelper {View getDayView(int position, View convertView, ViewGroup parent, DateTime dateTime, boolean select);View getWeekView(int position, View convertView, ViewGroup parent, String week);}

显示星期:

还记得前面说的显示星期的是个GridView,那么在设置Adapter的时候这样写就可以了:

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return getViewHelper.getWeekView(position, convertView, parent, weeks.get(position));}

显示日期:

日期显示稍微复杂一点,最关键的是重写ViewPager的Adapter。

因为有关时间的处理使用的是jodatime,在初始化PagerAdapter的时候会传今天所在这一周的第一天(从周日开始显示),每滑动一页就可以根据这个时间减去或加上一周,jodatime中刚好有相应的api,非常方便。

关键代码:

@Overridepublic View getView(int position, View convertView, ViewGroup container) {WeekViewHolder viewHolder;if(convertView == null){convertView = LayoutInflater.from(context).inflate(R.layout.item_calendar, container, false);viewHolder = new WeekViewHolder(convertView);convertView.setTag(viewHolder);} else {viewHolder = (WeekViewHolder) convertView.getTag();}int intervalWeeks = position - centerPosition;DateTime start = startDateTime.plusWeeks(intervalWeeks);final DayAdapter dayAdapter = new DayAdapter(start, getViewHelper, selectDateTime);viewHolder.weekGrid.setAdapter(dayAdapter);viewHolder.weekGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {selectDateTime = dayAdapter.getItem(position);dayAdapter.setSelectDateTime(selectDateTime);notifyDataSetChanged();if(dateSelectListener != null){dateSelectListener.onDateSelect(selectDateTime);}}});return convertView;}

根据position,可以计算出显示的这一周的第一天日期。
int intervalWeeks = position - centerPosition;
DateTime start = startDateTime.plusWeeks(intervalWeeks);

显示一周日期:

初始化一周的日期,

    public DayAdapter(DateTime startDateTime, GetViewHelper getViewHelper, DateTime selectDateTime) {this.getViewHelper = getViewHelper;this.selectDateTime = selectDateTime;dateTimes = new ArrayList<>();for (int i = 0; i < DAYS_OF_WEEK; i++) {dateTimes.add(new DateTime(startDateTime).plusDays(i));}}

日期显示通过接口返回给使用者处理。

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return getViewHelper.getDayView(position, convertView, parent, dateTimes.get(position), CalendarUtil.isSameDay(dateTimes.get(position), selectDateTime));}

添加一些公有方法:

  • setSelectDateTime(DateTime dateTime) 设置选中日期

在PagerAdapter中有一个成员变量是selectDateTime(默认是今天被选中),在显示一周日期的时候会把selectDateTime作为构造参数传递给DayAdapter,在DayAdapter的getView方法中国会判断显示的这一天是不是选中日期。

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return getViewHelper.getDayView(position, convertView, parent, dateTimes.get(position), CalendarUtil.isSameDay(dateTimes.get(position), selectDateTime));}

需要注意的是:设置选择日期后要调用PagerAdapter的notifyDataSetChanged()方法,要想这个方法起作用,需要重写PagerAdapter的getItemPosition方法。

    @Overridepublic int getItemPosition(Object object) {return POSITION_NONE;}
  • gotoDate(DateTime dateTime) 跳转到指定日期

相当于重新初始化一遍,只是显示的时间为跳转日期的那一周。

    public void gotoDate(DateTime dateTime){viewPagerContent.setCurrentItem(centerPosition, true);calendarPagerAdapter.setStartDateTime(dateTime.minusDays(dateTime.getDayOfWeek()));onWeekChange(centerPosition);}
  • getCurrentFirstDay 获取当前页面第一天

根据当前ViewPager的position和centerPosition比较,加上jodatime的api,很简单就实现了。

public DateTime getCurrentFirstDay(){int intervalWeeks = viewPagerContent.getCurrentItem() - centerPosition;return calendarPagerAdapter.getStartDateTime().plusWeeks(intervalWeeks);}
  • refresh 刷新界面

这个方法是很有必要的,因为你可能要添加事件,而事件是从网络获取的。

    public void refresh(){calendarPagerAdapter.notifyDataSetChanged();}

关于监听:
这里提供了两种监听,日期选择监听,周变化监听

public interface DateSelectListener {void onDateSelect(DateTime selectDate);
}
public interface WeekChangeListener {void onWeekChanged(DateTime firstDayOfWeek);
}

实现:

  • 周变化监听

监听ViewPager页面选择监听,根据position计算出当前显示周的第一天日期。

viewPagerContent.addOnPageChangeListener(new CustomPagerChandeListender() {@Overridepublic void onPageSelected(int position) {onWeekChange(position);}});private void onWeekChange(int position) {int intervalWeeks = position - centerPosition;DateTime firstDayofWeek = calendarPagerAdapter.getStartDateTime().plusWeeks(intervalWeeks);if(weekChangedListener != null){weekChangedListener.onWeekChanged(firstDayofWeek);}}
  • 日期选择监听

日期选择监听就是监听GridView的item点击。

 viewHolder.weekGrid.setAdapter(dayAdapter);viewHolder.weekGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {selectDateTime = dayAdapter.getItem(position);dayAdapter.setSelectDateTime(selectDateTime);notifyDataSetChanged();if(dateSelectListener != null){dateSelectListener.onDateSelect(selectDateTime);}}});

使用

布局:

    <com.beiing.weekcalendar.WeekCalendarandroid:id="@+id/week_calendar"android:layout_width="match_parent"android:layout_height="wrap_content"app:wc_headerBgColor="#ccc"app:wc_headerHeight="60dp"app:wc_calendarHeight="55dp" />

代码中:

  • 设置布局显示

必须调用setGetViewHelper方法加载布局,getDayView方法控制每一天显示,
getWeekView方法控制星期显示,使用类似ListView中BaseAdapter中的getView方法。

        weekCalendar.setGetViewHelper(new GetViewHelper() {@Overridepublic View getDayView(int position, View convertView, ViewGroup parent, DateTime dateTime, boolean select) {if(convertView == null){convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_day, parent, false);}TextView tvDay = (TextView) convertView.findViewById(R.id.tv_day);tvDay.setText(dateTime.toString("d"));if(CalendarUtil.isToday(dateTime) && select){tvDay.setTextColor(Color.WHITE);tvDay.setBackgroundResource(R.drawable.circular_blue);} else if(CalendarUtil.isToday(dateTime)){tvDay.setTextColor(getResources().getColor(R.color.colorTodayText));tvDay.setBackgroundColor(Color.TRANSPARENT);} else if(select){tvDay.setTextColor(Color.WHITE);tvDay.setBackgroundResource(R.drawable.circular_blue);} else {tvDay.setTextColor(Color.BLACK);tvDay.setBackgroundColor(Color.TRANSPARENT);}ImageView ivPoint = (ImageView) convertView.findViewById(R.id.iv_point);ivPoint.setVisibility(View.GONE);for (DateTime d : eventDates) {if(CalendarUtil.isSameDay(d, dateTime)){ivPoint.setVisibility(View.VISIBLE);break;}}return convertView;}@Overridepublic View getWeekView(int position, View convertView, ViewGroup parent, String week) {if(convertView == null){convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_week, parent, false);}TextView tvWeek = (TextView) convertView.findViewById(R.id.tv_week);tvWeek.setText(week);if(position == 0 || position == 6){tvWeek.setTextColor(getResources().getColor(R.color.colorAccent));}return convertView;}});
  • 设置日期选择监听
weekCalendar.setDateSelectListener(new DateSelectListener() {@Overridepublic void onDateSelect(DateTime selectDate) {String text = "你选择的日期是:" + selectDate.toString("yyyy-MM-dd");tvSelectDate.setText(text);}});
  • 设置周变化监听
weekCalendar.setWeekChangedListener(new WeekChangeListener() {@Overridepublic void onWeekChanged(DateTime firstDayOfWeek) {String text = "本周第一天:" + firstDayOfWeek.toString("yyyy年M月d日")+ ",本周最后一天:" + new DateTime(firstDayOfWeek).plusDays(6).toString("yyyy年M月d日");tvWeekChange.setText(text);}});

其他方法

  • getSelectDateTime 获取当前选中日期

  • setSelectDateTime(DateTime dateTime) 设置选中日期

  • gotoDate(DateTime dateTime) 跳转到指定日期

  • getCurrentFirstDay 获取当前页面第一天

  • refresh 刷新界面


月日历

地址: https://github.com/LineChen/Month_Calendar

设计与周日历一样,不同的是在日期显示中,一个是按周显示,一个是按月显示。实现中处理的不同主要在DayAdapter中,构造方法中要初始化这个月显示的日期。

 public DayAdapter(int calendarHeight, DateTime startDateTime, GetViewHelper getViewHelper, DateTime selectDateTime) {this.calendarHeight = calendarHeight;this.getViewHelper = getViewHelper;this.selectDateTime = selectDateTime;dateTimes = new ArrayList<>();final int daysOfMonth = startDateTime.dayOfMonth().getMaximumValue();int firstDayOfWeek = startDateTime.getDayOfWeek() % DAYS_OF_WEEK;for (int i = firstDayOfWeek; i >= 1; i--) {dateTimes.add(new Day(new DateTime(startDateTime).minusDays(i), true));}for (int i = 0; i < daysOfMonth; i++) {dateTimes.add(new Day(new DateTime(startDateTime).plusDays(i), false));}DateTime lastDay = dateTimes.get(dateTimes.size() - 1).getDateTime();int yy = DAYS_OF_WEEK - lastDay.getDayOfWeek() % DAYS_OF_WEEK;for (int i = 1; i < yy; i++) {dateTimes.add(new Day(new DateTime(lastDay).plusDays(i), true));}}

然后是在getView中会对视图进行高度设置,因为ViewPager高度时固定的,有些月份要显示5行,有些月份显示6行。

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {Day day = dateTimes.get(position);day.setSelect(CalendarUtil.isSameDay(day.getDateTime(), selectDateTime));View view = getViewHelper.getDayView(position, convertView, parent, day);ViewGroup.LayoutParams params = view.getLayoutParams();params.height = calendarHeight / (dateTimes.size() / DAYS_OF_WEEK);return view;}

使用

布局:

<com.beiing.monthcalendar.MonthCalendarandroid:id="@+id/month_calendar"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@android:color/white"app:mc_calendarHeight="@dimen/calender_content_height"/>

代码中:

  • 设置布局显示

必须调用setGetViewHelper方法加载布局,getDayView方法控制每一天显示,
getWeekView方法控制星期显示,使用类似ListView中BaseAdapter中的getView方法。

monthCalendar.setGetViewHelper(new GetViewHelper() {@Overridepublic View getDayView(int position, View convertView, ViewGroup parent, Day day) {if(convertView == null){convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_day, parent, false);}TextView tvDay = (TextView) convertView.findViewById(R.id.tv_day);DateTime dateTime = day.getDateTime();tvDay.setText(dateTime.toString("d"));boolean select = day.isSelect();if(CalendarUtil.isToday(dateTime) && select){tvDay.setTextColor(Color.WHITE);tvDay.setBackgroundResource(R.drawable.circular_blue);} else if(CalendarUtil.isToday(dateTime)){tvDay.setTextColor(getResources().getColor(R.color.colorTodayText));tvDay.setBackgroundColor(Color.TRANSPARENT);} else if(select){tvDay.setTextColor(Color.WHITE);tvDay.setBackgroundResource(R.drawable.circular_blue);} else {tvDay.setBackgroundColor(Color.TRANSPARENT);if(day.isOtherMonth()){tvDay.setTextColor(Color.LTGRAY);} else {tvDay.setTextColor(Color.BLACK);}}ImageView ivPoint = (ImageView) convertView.findViewById(R.id.iv_point);ivPoint.setVisibility(View.INVISIBLE);for (DateTime d : eventDates) {if(CalendarUtil.isSameDay(d, dateTime)){ivPoint.setVisibility(View.VISIBLE);break;}}return convertView;}@Overridepublic View getWeekView(int position, View convertView, ViewGroup parent, String week) {if(convertView == null){convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_week, parent, false);}TextView tvWeek = (TextView) convertView.findViewById(R.id.tv_week);switch (position){case 0:week = "日";tvWeek.setTextColor(getResources().getColor(R.color.colorAccent));break;case 1:week = "一";break;case 2:week = "二";break;case 3:week = "三";break;case 4:week = "四";break;case 5:week = "五";break;case 6:week = "六";tvWeek.setTextColor(getResources().getColor(R.color.colorAccent));break;}tvWeek.setText(week);return convertView;}});
  • 设置日期选择监听
monthCalendar.setOnDateSelectListener(new OnDateSelectListener() {@Overridepublic void onDateSelect(DateTime selectDate) {tvSelectDate.setText("你选择的日期:" + selectDate.toString("yyyy-MM-dd"));}});
  • 设置月切换监听

monthCalendar.setOnMonthChangeListener(new OnMonthChangeListener() {@Overridepublic void onMonthChanged(int currentYear, int currentMonth) {tvMonthChange.setText(currentYear + "年" + currentMonth + "月");}});

其他方法

  • getSelectDateTime 获取当前选中日期

  • setSelectDateTime(DateTime dateTime) 设置选中日期

  • gotoDate(DateTime dateTime) 跳转到指定日期

  • getCurrentYear 获取当前显示年份

  • getCurrentMonth 获取当前显示月份

  • refresh 刷新界面

按周显示的日历和按月显示的日历,你需要吗相关推荐

  1. android 日历 周显示,按周显示的日历和按月显示的日历,你需要吗

    周日历 使用 布局: android:id="@+id/week_calendar" android:layout_width="match_parent" a ...

  2. 外贸日历|2月海外营销日历

    一年之计在于春.2月,外贸企业开始复工复产,开始进行新一年的生产计划. 2月是浪漫.狂欢.庆祝.赞颂的月份,情人节.狂欢节等各种节日接踵而至.一次好的节日借势营销,会帮助出海品牌扎根当地市场,开展更多 ...

  3. vue移动端项目日历组件,月周切换,点击进入上/下一个月

    项目场景: Vue移动端项目的日历组件,移动端如果没有别的特别要求,一般用vant中的日历组件就OK,这里用的另一个.组件是网上找的,原网址:vue-hash-calendar,需要的请自行去看. 我 ...

  4. 按月显示的万年历(含农历)网页代码

    /***************************************************************************** 按月显示的万年历(含农历)网页代码 *** ...

  5. linux系统使用命令一次显示日历,linux下的显示有中国农历的日历ccal

    cal: linux下显示日历的一般命令 使用格式usage: cal [-13smjyV] [[month] year][root@jacky ccal-2.5]# cal 2 2009 二月 20 ...

  6. 微信小程序自定义日历(带价格显示)

    JS代码: var Moment = require("../../utils/moment.js"); var DATE_YEAR = new Date().getFullYea ...

  7. 三周第三次课(12月27日)

    三周第三次课(12月27日) 3.7 su命令 su 切换用户 whoami id su -aming su aming 切换用户,但是没有切换家目录 su - -c "touch /tmp ...

  8. PHP第6周函数上机练习:实战输出2022年日历(含直播视频)

    直播回放 PHP第6周函数上机题(实战输出2022年日历) 题目答案 PHP动态网站开发-函数 一.单选 1.下列关键字中,用于函数返回的是(D ). A. continue B. break C. ...

  9. 怎么能让win10电脑日历便签上显示二十四节气?

    Win10电脑日历云便签兼具便签记事和日历月视图的功能,不仅能在日历中显示便签事项,还能在日历便签上显示二十四节气.那怎么能让这款win10电脑日历便签上显示二十四节气呢? 一.打开win10电脑日历 ...

  10. c语言怎么做12一个月的日历,请问用C语言写日历怎样一行输入三个月啊。我是一个月一个月输入的,不会把二月输入到一月后面,求帮忙...

    qq_qzuser_605 #include<stdio.h> #include <windows.h> //判断是否是闰年,是返回1,否返回0 bool isLeap(int ...

最新文章

  1. python中国大学排名爬虫写明详细步骤-python爬虫爬取2020年中国大学排名
  2. 柱底反力求和lisp软件_AutoLISP详细讲解
  3. android调试神器Stetho
  4. 北斗导航 | 北斗系统信息处理创新技术(学术PPT分享附视频)
  5. 【java】动态高并发时为什么推荐重入锁而不是Synchronized?
  6. 算法总结之 打印二叉树的边界节点
  7. 报线上python课程靠谱吗-Python培训线上和线下有什么区别?
  8. 详解MATLAB的函数uigetfile(),并利用它打开文件选择对话框,选择文件,返回文件名和文件路径
  9. 中职计算机vb听课记录,《高级语言程序设计VB》听课笔记:12
  10. elasticsearch7.5.0 集群搭建
  11. C#利用HttpClient获取微信Web扫描登录二维码
  12. Ternary Search Tree(三叉树)
  13. 年度催泪之作:2015中国程序员生存报告
  14. bzoj 1022: [SHOI2008]小约翰的游戏John anti_nim游戏
  15. eclipse 关闭英文拼写检查,关闭xml验证
  16. 计算机系统使用的cd-rom,如何将CD-ROM的内容复制到计算机[复制]
  17. require.js库
  18. 关于oracle数据库总结(三)
  19. HyperLPR车牌识别库代码分析总结(15)
  20. vue 启动没有不支持ip,只能localhost

热门文章

  1. 量子计算机 模拟,量子计算机首次模拟实现“时光倒流”
  2. java环境配置(jdk、jre安装和环境配置)
  3. OSX更新后JRE6被删除引发了问题
  4. Windows anaconda下载安装
  5. 电脑桌面双击计算机图标打不开,电脑双击图标打不开怎么办
  6. php网站服务器工具,PHP网站服务器管理软件LuManager1.1.9发布
  7. 数据挖掘工程师笔试及答案整理
  8. [WTL] 使用CImageList
  9. Unity3D面试总结
  10. Retrofit完美封装