按周显示的日历和按月显示的日历,你需要吗
来源:互联网 发布:谢娜主持的网络综艺 编辑:程序博客网 时间:2024/06/05 02:43
周日历
地址: 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使用缓存,详细信息请看源码
@Override public 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; }
@Override public 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的时候这样写就可以了:
@Override public View getView(int position, View convertView, ViewGroup parent) { return getViewHelper.getWeekView(position, convertView, parent, weeks.get(position)); }
显示日期:
日期显示稍微复杂一点,最关键的是重写ViewPager的Adapter。
因为有关时间的处理使用的是jodatime,在初始化PagerAdapter的时候会传今天所在这一周的第一天(从周日开始显示),每滑动一页就可以根据这个时间减去或加上一周,jodatime中刚好有相应的api,非常方便。
关键代码:
@Override public 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() { @Override public 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)); } }
日期显示通过接口返回给使用者处理。
@Override public 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方法中国会判断显示的这一天是不是选中日期。
@Override public 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方法。
@Override public 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() { @Override public 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() { @Override public 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.WeekCalendar android: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() { @Override public 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; } @Override public 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() { @Override public void onDateSelect(DateTime selectDate) { String text = "你选择的日期是:" + selectDate.toString("yyyy-MM-dd"); tvSelectDate.setText(text); } });
- 设置周变化监听
weekCalendar.setWeekChangedListener(new WeekChangeListener() { @Override public 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行。
@Override public 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.MonthCalendar android: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() { @Override public 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; } @Override public 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() { @Override public void onDateSelect(DateTime selectDate) { tvSelectDate.setText("你选择的日期:" + selectDate.toString("yyyy-MM-dd")); } });
- 设置月切换监听
monthCalendar.setOnMonthChangeListener(new OnMonthChangeListener() { @Override public void onMonthChanged(int currentYear, int currentMonth) { tvMonthChange.setText(currentYear + "年" + currentMonth + "月"); } });
其他方法
getSelectDateTime
获取当前选中日期setSelectDateTime(DateTime dateTime)
设置选中日期gotoDate(DateTime dateTime)
跳转到指定日期getCurrentYear
获取当前显示年份getCurrentMonth
获取当前显示月份refresh
刷新界面
- 按周显示的日历和按月显示的日历,你需要吗
- java_calendar日历的显示
- 按月生成日历,以datatable形式显示。
- 一个简单的日历显示
- 还是日历类的显示
- 显示指定月份的日历
- 显示日历和天气
- My97DatePicker日历控制按日、按周和按月选择
- 日历显示
- 显示日历
- 显示日历
- 显示日历
- 显示日历
- 显示日历和时间的控件 js 时分秒
- 显示单月的日历的C程序
- 日历收集,显示当前的农历(javascript)
- 一个很不错的日历显示(JS)
- 显示日程的自定日历
- Java TimeZone 和 Linux TimeZone问题
- Android 记住密码功能
- C++语言例题
- 研究生期间读书目录
- UE4 自带的一些模块
- 按周显示的日历和按月显示的日历,你需要吗
- Windows7+WDK+VS2010+VisualDDK驱动开发环境搭建
- 为何编程如此之难?
- java动态创建xml文件
- 插入排序
- 从程序员代码“呼救”大破传销组织_聊掌握一门编程语言的重要性!
- Java 实例
- 1052. 卖个萌 (20) PAT
- CSDN日报20170526 ——《论程序员的时代焦虑与焦虑的缓解》