Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android自定義日歷

android自定義日歷

編輯:關於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,但是我把他封裝起來,直接調用就可以了。如果有需要的同學,可以直接下載就可以了。

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved