自定义CalendarView,可以以周视图或者月视图显示
来源:互联网 发布:ds18b20怎么接单片机 编辑:程序博客网 时间:2024/06/02 07:30
转载请注明转自,谢谢:http://blog.csdn.net/wmlove_hqy/article/details/46716951
首先分析一下功能。
1.能够左右滑动,这里选择通过ViewPager实现。
2.能够点击、选中日期,说明每一天是一个单独的View,选中的状态的变化改变,这里用StateDrawbleList实现。
3.通过Calendar提供的方法实现数据填充。
我们先来看看效果。
好,让我们开始吧!
我首先在这里定义一个DayView.
public class DayView extends TextView{ private int backgroupColor = Color.GREEN; private Date date; private int day; private int month; public DayView(Context context) { super(context); setTextAlignment(TEXT_ALIGNMENT_CENTER); setBackgroupColor(); setTextSize(20); setHeight(150); setWidth(150); setTextColor(Color.BLACK); setGravity(Gravity.CENTER); } //提供更改选中之后背景颜色 public void setSelectColor(int color){ this.backgroupColor = color; setBackgroupColor(); postInvalidate(); } private void setBackgroupColor(){ //设置点击时改变背景色 StateListDrawable drawable = new StateListDrawable(); ShapeDrawable shape = new ShapeDrawable(new OvalShape()); shape.setShaderFactory(new ShapeDrawable.ShaderFactory() { @Override public Shader resize(int i, int i1) { return new LinearGradient(0,0,0,0,backgroupColor,backgroupColor, Shader.TileMode.REPEAT); } }); drawable.addState(new int[]{android.R.attr.state_selected}, shape); setBackground(drawable); } //设置具体的日期 public void setDay(boolean showotherdays,boolean inrange){ //判断是否显示除了这个月份之外的日期。 //默认不显示 //当视图为周视图时,默认为真 if(!showotherdays){ String text = inrange ? day+"" : ""; boolean enable = inrange ? true : false; setEnabled(enable); setText(text); return; } setText(String.valueOf(day)); } //供外部调用,接受具体日期 public void setTimeRange(Calendar calendar) { this.day = calendar.get(Calendar.DAY_OF_MONTH); this.month = calendar.get(Calendar.MONTH); this.date = calendar.getTime(); } public String getTime(){ String time; SimpleDateFormat format = new SimpleDateFormat("dd MMMM", Locale.ENGLISH); time = format.format(date); return time; } public Date getDate(){ return this.date; } }
这就表示每一天的日期,只需要实例化出来并且设置他的日期。
每一天有了,现在需要一个容器把他放进去,可以是一个月,或者是一周。
所以我定义了一个TimeView来放这些Day.
public class TimeView extends RelativeLayout implements View.OnClickListener{ //每个星期有的天数 private static final int DEFAULT_DAY_IN_WEEK = 7; //一个月有几个星期,为月视图的时候默认是 6个星期,周视图为 1个星期。 private int WEEK_IN_MONTH; //用来表示周视图或者月视图的flag private int timeflag; private boolean showOtherDay; private List<DayView> dayViewList; private Calendar mCalendarCurrent = null; //当Day被选中时候的回调 private OnDaySelectListener mDaySelectCallBack; //当Day选中状态切换的时候的回调 private OnDaySelectChangeListener mOnDaySelectChangeListener; public void setOnDaySelectListener(OnDaySelectListener mDaySelectCallBack) { this.mDaySelectCallBack = mDaySelectCallBack; } public void setOnDaySelectChangeListener(OnDaySelectChangeListener onDaySelectChangeListener){ this.mOnDaySelectChangeListener = onDaySelectChangeListener; } public TimeView(Context context,Calendar calendarCurrent,int timeflag) { super(context); mCalendarCurrent = CalendarUtils.getCalenar(); CalendarUtils.copyTo(calendarCurrent,mCalendarCurrent); showOtherDay = false; timeflag = Calendar.MONTH; dayViewList = new ArrayList<>() WEEK_IN_MONTH = (timeflag==Calendar.MONTH) ? 6 : 1; showOtherDay = (timeflag==Calendar.WEEK_OF_YEAR) ? true : false; setUpView(); setDayView(timeflag); } //画出每一行,填充后用来显示一周 private LinearLayout makeRow(){ LinearLayout row = new LinearLayout(getContext()); row.setOrientation(LinearLayout.HORIZONTAL); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,0,1f); row.setLayoutParams(params); return row; } //把周视图或者月视图画出来 private void setUpView() { LinearLayout root = new LinearLayout(getContext()); root.setOrientation(LinearLayout.VERTICAL); LinearLayout row; for(int i=0;i<WEEK_IN_MONTH;i++){ row = makeRow(); for(int x=0;x<DEFAULT_DAY_IN_WEEK;x++){ DayView day = new DayView(getContext()); day.setOnClickListener(this); row.addView(day, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f)); dayViewList.add(day); } root.addView(row); } addView(root, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)); } //把每一个DayView设置日期 private void setDayView(int timeflag){ Calendar calendar = getWorkingCalendar(); for(DayView dayView : dayViewList){ dayView.setTimeRange(calendar); dayView.setDay(showOtherDay, calendar.get(timeflag) == mCalendarCurrent.get(timeflag)); calendar.add(Calendar.DATE,1); } } //把Calendar设置为每个月或者每个星期的第一天 private Calendar getWorkingCalendar(){ Calendar calendar = CalendarUtils.getCalenar(); CalendarUtils.copyTo(mCalendarCurrent, calendar); if(timeflag==Calendar.MONTH){CalendarUtils.setToFirstDayInMonth(calendar);} CalendarUtils.setToFirstDayInWeek(calendar); return calendar; } public Calendar getTimeCalendar(){ Log.i("TAG",mCalendarCurrent.getTime()+"Timecurrent"); return this.mCalendarCurrent; } public Date getDate(){ return this.mCalendarCurrent.getTime(); } public void setSelectColor(int color){ for(DayView dayView : dayViewList){ dayView.setSelectColor(color); } } public void setTimeFlag(int timeflag){ this.timeflag = timeflag; } //处理点击事件 @Override public void onClick(View view) { String time = null; Date date = null; if(view instanceof DayView){ clearSelected(); DayView dayView = (DayView) view; dayView.setSelected(true); Toast.makeText(getContext(),dayView.getText(),Toast.LENGTH_SHORT).show(); time = dayView.getTime(); date = dayView.getDate(); postInvalidate(); } mDaySelectCallBack.OnDaySelect(time,date); mOnDaySelectChangeListener.SelectChangeCallBack(); } //用于清除其他TimeView的选中状态 public void clearSelected() { for(DayView other : dayViewList){ other.setSelected(false); } }}
这就表示一个月或者一个星期的View,其实也就是ViewPager中的一个Item。
OnDaySelectListener 和OnDaySelectChangeListener 是定义用来回调的接口。
CalendarUtils是一个工具类。
那么有了Item,接下来就是添加到ViewPager中了。
而ViewPager也是放在一个容器之中,构成了这整个CalendarView。
public class CalendarView extends RelativeLayout { private ViewPager mViewPager; private CalendarViewAdapter mCalendarViewAdapter; private DaySelectChanegListener mDaySelectChanegListener = new DaySelectChanegListener(); //默认是显示月视图的 private boolean inweek = false; private int TimeFlag ; private List<TimeView> timeViewList = new ArrayList<>(); private List<DaySelectChanegListener> OnTimeChangeListenerList = new ArrayList<>(); private Calendar mCalendarMax = null; private Calendar mCalendarMin = null; private Calendar mCalendarCurrent = null; private OnTimeChangeListener mOnTimeChangeListener = null; public int getTimeFlag(boolean inweek) { return inweek ? Calendar.WEEK_OF_YEAR : Calendar.MONTH; } //把除了选中的Day所在的TimeView之外的day全部设置为非选中状态 private class DaySelectChanegListener implements OnDaySelectChangeListener { @Override public void SelectChangeCallBack() { TimeView current = timeViewList.get(mViewPager.getCurrentItem()); for (TimeView other : timeViewList) { if (other!=current){other.clearSelected();} } } } public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray t = context.obtainStyledAttributes(attrs,R.styleable.CalendarView); inweek = t.getBoolean(R.styleable.CalendarView_viewinview,false); t.recycle(); TimeFlag = getTimeFlag(inweek); LinearLayout root = new LinearLayout(context); root.setOrientation(LinearLayout.VERTICAL); addTimeView(); LinearLayout title = new LinearLayout(context); title.setOrientation(LinearLayout.HORIZONTAL); Calendar calendar = CalendarUtils.getCalenar(); CalendarUtils.setToFirstDayInWeek(calendar); SimpleDateFormat format = new SimpleDateFormat("EEE", Locale.ENGLISH); for (int i = 0; i < 7; i++) { TextView textView = new TextView(context); textView.setWidth(150); textView.setHeight(150); textView.setGravity(Gravity.CENTER); textView.setTextAlignment(TEXT_ALIGNMENT_CENTER); textView.setTextColor(Color.BLACK); textView.setText(format.format(calendar.getTime())); Log.i("TAG", format.format(calendar.getTime())); calendar.add(Calendar.DATE, 1); title.addView(textView); } Log.i("TAG", title.getChildCount() + "childcount"); root.addView(title); mViewPager = new ViewPager(context); mCalendarViewAdapter = new CalendarViewAdapter(); mViewPager.setAdapter(mCalendarViewAdapter); mViewPager.setCurrentItem(getIndex()); mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @Override public void onPageSelected(int position) { TimeView timeView = timeViewList.get(position); Date date = timeView.getDate(); mOnTimeChangeListener.OnTimeChange(date); } @Override public void onPageScrollStateChanged(int state) {} }); root.addView(mViewPager, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); addView(root); } //当前的ViewPager中的TimeView因为滑动而改变时的回调。 public void setOnTimeChangeListener(OnTimeChangeListener listener){ if(listener!=null){ this.mOnTimeChangeListener = listener; } else throw new NullPointerException("OnTimeChangeListener can not be null!"); } public void setOnDaySelectListener(OnDaySelectListener listener){ if(listener!=null){ for(TimeView timeView : timeViewList){ timeView.setOnDaySelectListener(listener); } } else throw new NullPointerException("OnDaySelectListener can not be null!"); } //设置可以显示的最大日期 public void setMaxDate(Calendar calendarMax){ this.mCalendarMax = calendarMax; postInvalidate(); } //设置可以显示的最小日期 public void setMinDate(Calendar calendarMin){ this.mCalendarMin = calendarMin; postInvalidate(); } public void setSelectColor(int color){ for(TimeView timeView : timeViewList){ timeView.setSelectColor(color); } } //设置当前的日期 public void setCurrentCalendar(Calendar currentCalendar){ this.mCalendarCurrent = currentCalendar; postInvalidate(); } //得到可以显示的最小Calendar private Calendar getMinCalendarDay(){ if(mCalendarMin==null){ int mindate = -2; Calendar min = CalendarUtils.getCalenar(); min.add(Calendar.YEAR, mindate); return min; } return mCalendarMin; } //得到可以显示的最大Calendar private Calendar getMaxCalendarDay(){ if(mCalendarMax==null){ int maxdate = 2; Calendar max = CalendarUtils.getCalenar(); max.add(Calendar.YEAR,maxdate); return max; } return mCalendarMax; } //把符合条件的TimeView添加到集合当中 private void addTimeView(){ Calendar minCalendar = getMinCalendarDay(); Calendar maxCalendar = getMaxCalendarDay(); if(mCalendarCurrent==null){ mCalendarCurrent = CalendarUtils.getCalenar(); } CalendarUtils.copyTo(minCalendar,mCalendarCurrent); Log.i("TAG",minCalendar.getTime()+"minCalendar"+maxCalendar.getTime()+"maxCalendar"+mCalendarCurrent.getTime()+"mCalendarCurrent"); while (CalendarUtils.isBefore(mCalendarCurrent, maxCalendar)){ TimeView timeView = new TimeView(getContext(),mCalendarCurrent,TimeFlag); timeView.setOnDaySelectChangeListener(mDaySelectChanegListener); timeViewList.add(timeView); mCalendarCurrent.add(TimeFlag, 1); } } //得到当前日期的Index private int getIndex(){ Calendar c = CalendarUtils.getCalenar(); for(int i=0;i<timeViewList.size();i++){ TimeView timeView = timeViewList.get(i); Calendar other = timeView.getTimeCalendar(); if(c.get(Calendar.YEAR)==other.get(Calendar.YEAR) &&c.get(Calendar.MONTH)==other.get(Calendar.MONTH)){ if(TimeFlag==Calendar.WEEK_OF_YEAR){ if(c.get(Calendar.WEEK_OF_YEAR)==other.get(Calendar.WEEK_OF_YEAR)){return i;} } return i; } } return 0; } //ViewPager的适配器 private class CalendarViewAdapter extends PagerAdapter{ @Override public int getCount() { return timeViewList.size(); } @Override public boolean isViewFromObject(View view, Object o) { return view == o; } @Override public Object instantiateItem(ViewGroup container, int position) { TimeView timeView = timeViewList.get(position); Log.i("TAG",timeViewList.size()+"size"); container.addView(timeView); return timeViewList.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(timeViewList.get(position)); } }}
到此就完成了这一个自定义的CalendarView,很简单吧。
总结一下。
主要是ViewPager中Item数据的填充,通过Calendar提供的一些方法就可以轻松的把你需要的日期筛选出来。然后就是把这些日期通过简单的逻辑判断填充到每一个所需要的View中,再就当做Item显示出来。还有一些基本的功能,如选中某一天能够回调这一天的日期,当前显示的月或者周是第几周或者哪一个月,再就是能够设置显示的最大日期和最小日期,选中某一天时的背景。最后是我主要想实现的,能够通过在布局文件中设置CalendarView是显示月视图还是周视图。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:wmlove="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <wmlove.library.CalendarView wmlove:viewinview="false" android:id="@+id/calendarview" android:layout_width="wrap_content" android:layout_height="wrap_content"> </wmlove.library.CalendarView></RelativeLayout>
如果有考虑不周到的地方还提出,一同探讨,谢谢。
也可以去我的GitHubh上给我Pull Requests,或者提issues
https://github.com/t154191277/CalendarView-Android
源代码下载地址:http://download.csdn.net/detail/wmlove_hqy/8859825
- 自定义CalendarView,可以以周视图或者月视图显示
- CalendarView(日历视图)
- Android之CalendarView日历视图
- FullCalendar在周视图和日视图中显示,但月视图显示正常
- CalendarView功能与用法(日历视图)
- UI组件:日历视图(CalendarView)
- 基于ViewPager+Recyclerview实现的CalendarView视图
- CalendarView功能与用法(日历视图)
- odoo10创建calendarView(日历视图)
- 自定义UICollectionView的头视图或者尾视图(UICollectionReusableView)
- 自定义视图-马赛克视图
- 自定义视图
- 自定义视图
- 自定义视图
- 自定义视图
- 自定义视图
- 自定义视图
- 自定义视图
- 重新思考ajax 与 http
- Git版本控制与工作流
- 1013. 股票风云
- fragment在锁屏解锁后出现重新onCreate解决办法
- atoi代码实现
- 自定义CalendarView,可以以周视图或者月视图显示
- Java中判断一个IP地址是否在一个网段内
- 2015070104 - EffactiveJava笔记 - 第48条 获取精确结果不用float或double(1)
- Swift 字符串
- MUTF-8编码格式介绍
- hdu2015面临小问题的反思
- Oracle 将表中两列的内容合并到另外一列当中去
- Linux平台的4个最佳开源代码编辑器
- 黑马程序员------数据类型与运算概述