当前位置: 代码迷 >> Android >> android自定义年历
  详细解决方案

android自定义年历

热度:92   发布时间:2016-04-28 04:26:22.0
android自定义日历

前几天闲来无事,变想做一些小工具玩玩。花了一天多的时间,弄出一个简单日历的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



1楼u011731233昨天 19:37
个人感觉有了月形式的,周的有点多余,没有多大改变
  相关解决方案