前几天闲来无事,变想做一些小工具玩玩。花了一天多的时间,弄出一个简单日历的View。分为月份模式和星期模式。滚动查看,先上图看看:
上面的是显示的是月份的模式。下面是星期的模式:
一个很简单的自定义View,然后通过Viewpager的OnpageChangeListener进行刷新View的数据。Viewpager通过轮回使用View。我默认设置是5个。可以左右无限切换。
下面是自定义CalendarView:
package com.example.calendar; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; public class CalendarView extends View { private static final String TAG = "CalendarView"; /** * 两种模式 (月份和星期) */ public static final int MONTH_STYLE = 0; public static final int WEEK_STYLE = 1; private static final int TOTAL_COL = 7; private static final int TOTAL_ROW = 6; private Paint mCirclePaint; private Paint mTextPaint; private int mViewWidth; private int mViewHight; private int mCellSpace; private Row rows[] = new Row[TOTAL_ROW]; private int mShowYear;//view显示的年份 private int mShowMonth;//view显示的月份 private int mShowDay;//针对星期样式 显示的开始的天 protected int defaultStyle = MONTH_STYLE; private static final int WEEK = 7; public CalendarView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CalendarView(Context context) { super(context); init(); } public CalendarView(Context context, int style) { super(context); this.defaultStyle = style; init(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); fillDate(); for (int i = 0; i < TOTAL_ROW; i++) { if (rows[i] != null) rows[i].drawCells(canvas, i); } } private void init() { mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mCirclePaint.setStyle(Paint.Style.FILL); mCirclePaint.setColor(Color.parseColor("#F24949")); initDate(); } private void initDate(){ if(defaultStyle == MONTH_STYLE){ mShowYear = DateUtil.getYear(); mShowMonth = DateUtil.getMonth(); mShowDay = 1; }else{ int time[] = DateUtil.getPerviousWeekSunday(); mShowYear = time[0]; mShowMonth = time[1]; mShowDay = time[2]; } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; mViewHight = h; mCellSpace = Math.min(mViewHight / TOTAL_ROW, mViewWidth / TOTAL_COL); mTextPaint.setTextSize(mCellSpace / 3); } //组 class Row { public Cell[] cells = new Cell[TOTAL_COL]; public void drawCells(Canvas canvas, int j) { for (int i = 0; i < cells.length; i++) { if (cells[i] != null) cells[i].drawSelf(canvas, i, j); } } } //单元格 class Cell { public String text; public State state; public Cell(String text, State state) { super(); this.text = text; this.state = state; } public void setText(String text) { this.text = text; } //绘制一个单元格 如果颜色需要自定义可以修改 public void drawSelf(Canvas canvas, int i, int j) { switch (state) { case CURRENT_MONTH_DAY: mTextPaint.setColor(Color.parseColor("#80000000")); break; case NEXT_MONTH_DAY: case PAST_MONTH_DAY: mTextPaint.setColor(Color.parseColor("#40000000")); break; case TODAY: mTextPaint.setColor(Color.parseColor("#fffffe")); canvas.drawCircle((float) (mCellSpace * (i + 0.45)), (float) ((j + 0.8) * mCellSpace), mCellSpace / 2, mCirclePaint); break; } //绘制文字 canvas.drawText(text, i * mCellSpace + mTextPaint.measureText("11"), (j + 1) * mCellSpace - mTextPaint.measureText(text, 0, 1) / 2, mTextPaint); } } enum State { CURRENT_MONTH_DAY, PAST_MONTH_DAY, NEXT_MONTH_DAY, TODAY; } /** * 填充日期的数据 */ private void fillDate() { if (defaultStyle == MONTH_STYLE) { fillMonthDate(); } else { fillWeekDate(); } } /** * 填充星期模式下的数据 * 默认通过当前日期得到所在星期天的日期,然后依次填充日期 */ private void fillWeekDate() { int currentMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth); rows[0] = new Row(); if(mShowDay + WEEK -1 > currentMonthDays){ mShowMonth += 1; } for (int i = 0; i < TOTAL_COL; i++) { mShowDay += 1; if (mShowDay > currentMonthDays) { mShowDay = 1; } if (mShowDay == DateUtil.getCurrentMonthDays()&& mShowYear == DateUtil.getYear() && mShowMonth == DateUtil.getMonth()) { rows[0].cells[i] = new Cell(mShowDay + "", State.TODAY); continue; } rows[0].cells[i] = new Cell(mShowDay + "", State.CURRENT_MONTH_DAY); } } /** * 填充月份模式下数据 * 通过getWeekDayFromDate得到一个月第一天是星期几就可以算出所有的日期的位置 * 然后依次填充 */ private void fillMonthDate() { int monthDay = DateUtil.getCurrentMonthDays(); int lastMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth - 1); int currentMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth); int firstDayWeek = DateUtil.getWeekDayFromDate(mShowYear, mShowMonth); boolean isCurrentMonth = false; if (mShowYear == DateUtil.getYear() && mShowMonth == DateUtil.getMonth()) { isCurrentMonth = true; } int time = 0; for (int j = 0; j < TOTAL_ROW; j++) { rows[j] = new Row(); for (int i = 0; i < TOTAL_COL; i++) { int postion = i + j * TOTAL_COL; if (postion >= firstDayWeek && postion < firstDayWeek + currentMonthDays) { time++; if (isCurrentMonth && time == monthDay) { rows[j].cells[i] = new Cell(time + "", State.TODAY); continue; } rows[j].cells[i] = new Cell(time + "", State.CURRENT_MONTH_DAY); continue; } else if (postion < firstDayWeek) { rows[j].cells[i] = new Cell((lastMonthDays - (firstDayWeek - postion - 1)) + "", State.PAST_MONTH_DAY); continue; } else if (postion >= firstDayWeek + currentMonthDays) { rows[j].cells[i] = new Cell((postion - firstDayWeek - currentMonthDays + 1) + "", State.NEXT_MONTH_DAY); } } } } //切换pager调用进行刷新 public void update(int year, int month,int day) { this.mShowMonth = month; this.mShowYear = year; this.mShowDay = day; invalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = measure(widthMeasureSpec); int height = measure(heightMeasureSpec); int d = Math.min(width, height); setMeasuredDimension(d, d); } protected int measure(int measureSpec) { int size = MeasureSpec.getSize(measureSpec); return size; } //为了方便viewPager生产出多个的CalendarView public static CalendarView[] createCalendarViewsForPager(Context context,int count,int style){ CalendarView[] views = new CalendarView[count]; for(int i = 0; i < count;i++){ views[i] = new CalendarView(context, style); } return views; } public static CalendarView[] createCalendarViewsForPager(Context context,int count){ CalendarView[] views = new CalendarView[count]; for(int i = 0; i < count;i++){ views[i] = new CalendarView(context, CalendarView.MONTH_STYLE); } return views; } }
我重写了ViewPagerAdapter。CalendarViewPagerAdapter实现了日历所需无限循环的功能,如果想使用就继承它。
package com.example.calendar; import android.os.Parcelable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.View; public class CalendarViewPagerAdapter extends PagerAdapter { private View[] views; public CalendarViewPagerAdapter(View[] views) { super(); this.views = views; } @Override public void finishUpdate(View arg0) { } @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); } @Override public int getCount() { return Integer.MAX_VALUE; } @Override public Object instantiateItem(View arg0, int arg1) { if (((ViewPager) arg0).getChildCount() == views.length) { ((ViewPager) arg0).removeView(views[arg1 % views.length]); } ((ViewPager) arg0).addView(views[arg1 % views.length], 0); return views[arg1 % views.length]; } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == (arg1); } @Override public Parcelable saveState() { return null; } @Override public void destroyItem(View arg0, int arg1, Object arg2) { // TODO Auto-generated method stub } @Override public void startUpdate(View arg0) { } }然后为了实现对CalendarView的滑动时的数据更新,我重写了OnPageChangeListener的方法。预留一个方法供activity界面进行回调onPageSelected(int year, int month, int day)。
package com.example.calendar; import android.support.v4.view.ViewPager.OnPageChangeListener; public class CalendarViewPagerLisenter implements OnPageChangeListener { private SildeDirection mDirection = SildeDirection.NO_SILDE; int mCurrIndex = 498; private static final int WEEK = 7; private int mShowYear; private int mShowMonth; private int mShowDay = 1; private CalendarView[] mShowViews; private int style; public CalendarViewPagerLisenter(CalendarView[] mShowViews) { super(); this.mShowViews = mShowViews; } public CalendarViewPagerLisenter(CalendarView[] mShowViews, int style) { super(); this.mShowViews = mShowViews; this.style = style; initDate(); } @Override public void onPageSelected(int arg0) { measureDirection(arg0); updateCalendarView(arg0); onPageSelected(mShowYear, mShowMonth, mShowDay); } private void updateCalendarView(int arg0) { if (style == CalendarView.MONTH_STYLE) updateMonthStyleCalendarView(); else if ((style == CalendarView.WEEK_STYLE)) updateWeekStyleCalendarView(); mShowViews[arg0 % mShowViews.length].update(mShowYear, mShowMonth, mShowDay); } private void updateWeekStyleCalendarView() { //int[] time = new int[3]; if (mDirection == SildeDirection.RIGHT) { int currentMonthDays = DateUtil.getMonthDays(mShowYear,mShowMonth); if(mShowDay + WEEK > currentMonthDays){ if(mShowMonth == 12){ mShowMonth = 1; mShowYear += 1; }else{ mShowMonth += 1; } mShowDay = WEEK -currentMonthDays + mShowDay; return; } mShowDay += WEEK; } else if (mDirection == SildeDirection.LEFT) { int lastMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth); if(mShowDay - WEEK < 1){ if(mShowMonth == 1){ mShowMonth = 12; mShowYear -= 1; }else{ mShowMonth -= 1; } mShowDay = lastMonthDays - WEEK + mShowDay; return; } mShowDay -= WEEK; } mDirection = SildeDirection.NO_SILDE; } private void updateMonthStyleCalendarView() { if (mDirection == SildeDirection.RIGHT) { if (mShowMonth == 12) { mShowMonth = 1; mShowYear += 1; } else { mShowMonth += 1; } } else if (mDirection == SildeDirection.LEFT) { if (mShowMonth == 1) { mShowMonth = 12; mShowYear -= 1; } else { mShowMonth -= 1; } } mDirection = SildeDirection.NO_SILDE; } private void measureDirection(int arg0) { if (arg0 > mCurrIndex) { mDirection = SildeDirection.RIGHT; } else if (arg0 < mCurrIndex) { mDirection = SildeDirection.LEFT; } mCurrIndex = arg0; } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { } public void onPageSelected(int year, int month, int day) { } enum SildeDirection { RIGHT, LEFT, NO_SILDE; } private void initDate(){ if(style == CalendarView.MONTH_STYLE){ mShowYear = DateUtil.getYear(); mShowMonth = DateUtil.getMonth(); mShowDay = 1; }else if(style == CalendarView.WEEK_STYLE){ int time[] = DateUtil.getPerviousWeekSunday(); mShowYear = time[0]; mShowMonth = time[1]; mShowDay = time[2]; } onPageSelected(mShowYear, mShowMonth, mShowDay); } public void setData(int style, CalendarView[] mShowViews){ this.style = style; this.mShowViews = mShowViews; } }
这是个简单的demo,但是我把他封装起来,直接调用就可以了。如果有需要的同学,可以直接下载就可以了。
下载地址:http://download.csdn.net/detail/huangyanbin123/7707617