日期控件Android 自定义日历控件

发一下牢骚和主题无关:

    

    有图有真像:

    

    日期和控件

    

    日历控件View:

/**

 * 日历控件 功能:获得点选的日期区间

 * 

 */

public class CalendarView extends View implements View.OnTouchListener {

	private final static String TAG = "anCalendar";

	private Date selectedStartDate;

	private Date selectedEndDate;

	private Date curDate; // 当前日历表现的月

	private Date today; // 明天的日期文字表现红色

	private Date downDate; // 手指按下状态时临时日期

	private Date showFirstDate, showLastDate; // 日历表现的第一个日期和最后一个日期

	private int downIndex; // 按下的格子索引

	private Calendar calendar;

	private Surface surface;

	private int[] date = new int[42]; // 日历表现数字

	private int curStartIndex, curEndIndex; // 当前表现的日历起始的索引

	//private boolean completed = false; // 为false表示只选择了开始日期,true表示结束日期也选择了

	//给控件设置监听事件

	private OnItemClickListener onItemClickListener;

	

	public CalendarView(Context context) {

		super(context);

		init();

	}



	public CalendarView(Context context, AttributeSet attrs) {

		super(context, attrs);

		init();

	}



	private void init() {

		curDate = selectedStartDate = selectedEndDate = today = new Date();

		calendar = Calendar.getInstance();

		calendar.setTime(curDate);

		surface = new Surface();

		surface.density = getResources().getDisplayMetrics().density;

		setBackgroundColor(surface.bgColor);

		setOnTouchListener(this);

	}



	@Override

	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		surface.width = getResources().getDisplayMetrics().widthPixels;

		surface.height = (int) (getResources().getDisplayMetrics().heightPixels*2/5);

//		if (View.MeasureSpec.getMode(widthMeasureSpec) == View.MeasureSpec.EXACTLY) {

//			surface.width = View.MeasureSpec.getSize(widthMeasureSpec);

//		}

//		if (View.MeasureSpec.getMode(heightMeasureSpec) == View.MeasureSpec.EXACTLY) {

//			surface.height = View.MeasureSpec.getSize(heightMeasureSpec);

//		}

		widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.width,

				View.MeasureSpec.EXACTLY);

		heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.height,

				View.MeasureSpec.EXACTLY);

		setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

	}



	@Override

	protected void onLayout(boolean changed, int left, int top, int right,

			int bottom) {

		Log.d(TAG, "[onLayout] changed:"

				+ (changed ? "new size" : "not change") + " left:" + left

				+ " top:" + top + " right:" + right + " bottom:" + bottom);

		if (changed) {

			surface.init();

		}

		super.onLayout(changed, left, top, right, bottom);

	}



	@Override

	protected void onDraw(Canvas canvas) {

		Log.d(TAG, "onDraw");

		// 画框

		canvas.drawPath(surface.boxPath, surface.borderPaint);

		// 年代

		//String monthText = getYearAndmonth();

		//float textWidth = surface.monthPaint.measureText(monthText);

		//canvas.drawText(monthText, (surface.width - textWidth) / 2f,

		//		surface.monthHeight * 3 / 4f, surface.monthPaint);

		// 上一月/下一月

		//canvas.drawPath(surface.preMonthBtnPath, surface.monthChangeBtnPaint);

		//canvas.drawPath(surface.nextMonthBtnPath, surface.monthChangeBtnPaint);

		// 礼拜

		float weekTextY = surface.monthHeight + surface.weekHeight * 3 / 4f;

		// 礼拜背景

//		surface.cellBgPaint.setColor(surface.textColor);

//		canvas.drawRect(surface.weekHeight, surface.width, surface.weekHeight, surface.width, surface.cellBgPaint);

		for (int i = 0; i < surface.weekText.length; i++) {

			float weekTextX = i

					* surface.cellWidth

					+ (surface.cellWidth - surface.weekPaint

							.measureText(surface.weekText[i])) / 2f;

			canvas.drawText(surface.weekText[i], weekTextX, weekTextY,

					surface.weekPaint);

		}

		

		// 计算日期

		calculateDate();

		// 按下状态,选择状态背景色

		drawDownOrSelectedBg(canvas);

		// write date number

		// today index

		int todayIndex = -1;

		calendar.setTime(curDate);

		String curYearAndMonth = calendar.get(Calendar.YEAR) + ""

				+ calendar.get(Calendar.MONTH);

		calendar.setTime(today);

		String todayYearAndMonth = calendar.get(Calendar.YEAR) + ""

				+ calendar.get(Calendar.MONTH);

		if (curYearAndMonth.equals(todayYearAndMonth)) {

			int todayNumber = calendar.get(Calendar.DAY_OF_MONTH);

			todayIndex = curStartIndex + todayNumber - 1;

		}

		for (int i = 0; i < 42; i++) {

			int color = surface.textColor;

			if (isLastMonth(i)) {

				color = surface.borderColor;

			} else if (isNextMonth(i)) {

				color = surface.borderColor;

			}

			if (todayIndex != -1 && i == todayIndex) {

				color = surface.todayNumberColor;

			}

			drawCellText(canvas, i, date[i] + "", color);

		}

		super.onDraw(canvas);

	}



	private void calculateDate() {

		calendar.setTime(curDate);

		calendar.set(Calendar.DAY_OF_MONTH, 1);

		int dayInWeek = calendar.get(Calendar.DAY_OF_WEEK);

		Log.d(TAG, "day in week:" + dayInWeek);

		int monthStart = dayInWeek;

		if (monthStart == 1) {

			monthStart = 8;

		}

		monthStart -= 1;  //以日为开头-1,以礼拜一为开头-2

		curStartIndex = monthStart;

		date[monthStart] = 1;

		// last month

		if (monthStart > 0) {

			calendar.set(Calendar.DAY_OF_MONTH, 0);

			int dayInmonth = calendar.get(Calendar.DAY_OF_MONTH);

			for (int i = monthStart - 1; i >= 0; i--) {

				date[i] = dayInmonth;

				dayInmonth--;

			}

			calendar.set(Calendar.DAY_OF_MONTH, date[0]);

		}

		showFirstDate = calendar.getTime();

		// this month

		calendar.setTime(curDate);

		calendar.add(Calendar.MONTH, 1);

		calendar.set(Calendar.DAY_OF_MONTH, 0);

		// Log.d(TAG, "m:" + calendar.get(Calendar.MONTH) + " d:" +

		// calendar.get(Calendar.DAY_OF_MONTH));

		int monthDay = calendar.get(Calendar.DAY_OF_MONTH);

		for (int i = 1; i < monthDay; i++) {

			date[monthStart + i] = i + 1;

		}

		curEndIndex = monthStart + monthDay;

		// next month

		for (int i = monthStart + monthDay; i < 42; i++) {

			date[i] = i - (monthStart + monthDay) + 1;

		}

		if (curEndIndex < 42) {

			// 表现了下一月的

			calendar.add(Calendar.DAY_OF_MONTH, 1);

		}

		calendar.set(Calendar.DAY_OF_MONTH, date[41]);

		showLastDate = calendar.getTime();

	}



	/**

	 * 

	 * @param canvas

	 * @param index

	 * @param text

	 */

	private void drawCellText(Canvas canvas, int index, String text, int color) {

		int x = getXByIndex(index);

		int y = getYByIndex(index);

		surface.datePaint.setColor(color);

		float cellY = surface.monthHeight + surface.weekHeight + (y - 1)

				* surface.cellHeight + surface.cellHeight * 3 / 4f;

		float cellX = (surface.cellWidth * (x - 1))

				+ (surface.cellWidth - surface.datePaint.measureText(text))

				/ 2f;

		canvas.drawText(text, cellX, cellY, surface.datePaint);

	}



	/**

	 * 

	 * @param canvas

	 * @param index

	 * @param color

	 */

	private void drawCellBg(Canvas canvas, int index, int color) {

		int x = getXByIndex(index);

		int y = getYByIndex(index);

		surface.cellBgPaint.setColor(color);

		float left = surface.cellWidth * (x - 1) + surface.borderWidth;

		float top = surface.monthHeight + surface.weekHeight + (y - 1)

				* surface.cellHeight + surface.borderWidth;

		canvas.drawRect(left, top, left + surface.cellWidth

				- surface.borderWidth, top + surface.cellHeight

				- surface.borderWidth, surface.cellBgPaint);

	}



	private void drawDownOrSelectedBg(Canvas canvas) {

		// down and not up

		if (downDate != null) {

			drawCellBg(canvas, downIndex, surface.cellDownColor);

		}

		// selected bg color

		if (!selectedEndDate.before(showFirstDate)

				&& !selectedStartDate.after(showLastDate)) {

			int[] section = new int[] { -1, -1 };

			calendar.setTime(curDate);

			calendar.add(Calendar.MONTH, -1);

			findSelectedIndex(0, curStartIndex, calendar, section);

			if (section[1] == -1) {

				calendar.setTime(curDate);

				findSelectedIndex(curStartIndex, curEndIndex, calendar, section);

			}

			if (section[1] == -1) {

				calendar.setTime(curDate);

				calendar.add(Calendar.MONTH, 1);

				findSelectedIndex(curEndIndex, 42, calendar, section);

			}

			if (section[0] == -1) {

				section[0] = 0;

			}

			if (section[1] == -1) {

				section[1] = 41;

			}

			for (int i = section[0]; i <= section[1]; i++) {

				drawCellBg(canvas, i, surface.cellSelectedColor);

			}

		}

	}



	private void findSelectedIndex(int startIndex, int endIndex,

			Calendar calendar, int[] section) {

		for (int i = startIndex; i < endIndex; i++) {

			calendar.set(Calendar.DAY_OF_MONTH, date[i]);

			Date temp = calendar.getTime();

			// Log.d(TAG, "temp:" + temp.toLocaleString());

			if (temp.compareTo(selectedStartDate) == 0) {

				section[0] = i;

			}

			if (temp.compareTo(selectedEndDate) == 0) {

				section[1] = i;

				return;

			}

		}

	}



	public Date getSelectedStartDate() {

		return selectedStartDate;

	}



	public Date getSelectedEndDate() {

		return selectedEndDate;

	}



	private boolean isLastMonth(int i) {

		if (i < curStartIndex) {

			return true;

		}

		return false;

	}



	private boolean isNextMonth(int i) {

		if (i >= curEndIndex) {

			return true;

		}

		return false;

	}



	private int getXByIndex(int i) {

		return i % 7 + 1; // 1 2 3 4 5 6 7

	}



	private int getYByIndex(int i) {

		return i / 7 + 1; // 1 2 3 4 5 6

	}



	// 获得当前应该表现的年代

	public String getYearAndmonth() {

		calendar.setTime(curDate);

		int year = calendar.get(Calendar.YEAR);

		int month = calendar.get(Calendar.MONTH);

		return year + "-" + surface.monthText[month];

	}

	

	//上一月

	public String clickLeftMonth(){

		calendar.setTime(curDate);

		calendar.add(Calendar.MONTH, -1);

		curDate = calendar.getTime();

		invalidate();

		return getYearAndmonth();

	}

	//下一月

	public String clickRightMonth(){

		calendar.setTime(curDate);

		calendar.add(Calendar.MONTH, 1);

		curDate = calendar.getTime();

		invalidate();

		return getYearAndmonth();

	}



	private void setSelectedDateByCoor(float x, float y) {

		// change month

//		if (y < surface.monthHeight) {

//			// pre month

//			if (x < surface.monthChangeWidth) {

//				calendar.setTime(curDate);

//				calendar.add(Calendar.MONTH, -1);

//				curDate = calendar.getTime();

//			}

//			// next month

//			else if (x > surface.width - surface.monthChangeWidth) {

//				calendar.setTime(curDate);

//				calendar.add(Calendar.MONTH, 1);

//				curDate = calendar.getTime();

//			}

//		}

		// cell click down

		if (y > surface.monthHeight + surface.weekHeight) {

			int m = (int) (Math.floor(x / surface.cellWidth) + 1);

			int n = (int) (Math

					.floor((y - (surface.monthHeight + surface.weekHeight))

							/ Float.valueOf(surface.cellHeight)) + 1);

			downIndex = (n - 1) * 7 + m - 1;

			Log.d(TAG, "downIndex:" + downIndex);

			calendar.setTime(curDate);

			if (isLastMonth(downIndex)) {

				calendar.add(Calendar.MONTH, -1);

			} else if (isNextMonth(downIndex)) {

				calendar.add(Calendar.MONTH, 1);

			}

			calendar.set(Calendar.DAY_OF_MONTH, date[downIndex]);

			downDate = calendar.getTime();

		}

		invalidate();

	}



	@Override

	public boolean onTouch(View v, MotionEvent event) {

		switch (event.getAction()) {

		case MotionEvent.ACTION_DOWN:

			setSelectedDateByCoor(event.getX(), event.getY());

			break;

		case MotionEvent.ACTION_UP:

			if (downDate != null) {

//				if (!completed) {

//					if (downDate.before(selectedStartDate)) {

//						selectedEndDate = selectedStartDate;

//						selectedStartDate = downDate;

//					} else {

//						selectedEndDate = downDate;

//					}

//					completed = true;

//				} else {

//					selectedStartDate = selectedEndDate = downDate;

//					completed = false;

//				}

				selectedStartDate = selectedEndDate = downDate;

				//响应监听事件

				onItemClickListener.OnItemClick(selectedStartDate);

				// Log.d(TAG, "downdate:" + downDate.toLocaleString());

				//Log.d(TAG, "start:" + selectedStartDate.toLocaleString());

				//Log.d(TAG, "end:" + selectedEndDate.toLocaleString());

				downDate = null;

				invalidate();

			}

			break;

		}

		return true;

	}

	

	//给控件设置监听事件

	public void setOnItemClickListener(OnItemClickListener onItemClickListener){

		this.onItemClickListener =  onItemClickListener;

	}

	//监听接口

	public interface OnItemClickListener {

		void OnItemClick(Date date);

	}



	/**

	 * 

	 * 1. 布局尺寸 2. 文字颜色,大小 3. 当前日期的颜色,选择的日期颜色

	 */

	private class Surface {

		public float density;

		public int width; // 整个控件的宽度

		public int height; // 整个控件的高度

		public float monthHeight; // 表现月的高度

		//public float monthChangeWidth; // 上一月、下一月按钮宽度

		public float weekHeight; // 表现礼拜的高度

		public float cellWidth; // 日期方框宽度

		public float cellHeight; // 日期方框高度	

		public float borderWidth;

		public int bgColor = Color.parseColor("#FFFFFF");

		private int textColor = Color.BLACK;

		//private int textColorUnimportant = Color.parseColor("#666666");

		private int btnColor = Color.parseColor("#666666");

		private int borderColor = Color.parseColor("#CCCCCC");

		public int todayNumberColor = Color.RED;

		public int cellDownColor = Color.parseColor("#CCFFFF");

		public int cellSelectedColor = Color.parseColor("#99CCFF");

		public Paint borderPaint;

		public Paint monthPaint;

		public Paint weekPaint;

		public Paint datePaint;

		public Paint monthChangeBtnPaint;

		public Paint cellBgPaint;

		public Path boxPath; // 边框路径

		//public Path preMonthBtnPath; // 上一月按钮三角形

		//public Path nextMonthBtnPath; // 下一月按钮三角形

		public String[] weekText = { "Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

		public String[] monthText = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

		   

		public void init() {

			float temp = height / 7f;

			monthHeight = 0;//(float) ((temp + temp * 0.3f) * 0.6);

			//monthChangeWidth = monthHeight * 1.5f;

			weekHeight = (float) ((temp + temp * 0.3f) * 0.7);

			cellHeight = (height - monthHeight - weekHeight) / 6f;

			cellWidth = width / 7f;

			borderPaint = new Paint();

			borderPaint.setColor(borderColor);

			borderPaint.setStyle(Paint.Style.STROKE);

			borderWidth = (float) (0.5 * density);

			// Log.d(TAG, "borderwidth:" + borderWidth);

			borderWidth = borderWidth < 1 ? 1 : borderWidth;

			borderPaint.setStrokeWidth(borderWidth);

			monthPaint = new Paint();

			monthPaint.setColor(textColor);

			monthPaint.setAntiAlias(true);

			float textSize = cellHeight * 0.4f;

			Log.d(TAG, "text size:" + textSize);

			monthPaint.setTextSize(textSize);

			monthPaint.setTypeface(Typeface.DEFAULT_BOLD);

			weekPaint = new Paint();

			weekPaint.setColor(textColor);

			weekPaint.setAntiAlias(true);

			float weekTextSize = weekHeight * 0.6f;

			weekPaint.setTextSize(weekTextSize);

			weekPaint.setTypeface(Typeface.DEFAULT_BOLD);

			datePaint = new Paint();

			datePaint.setColor(textColor);

			datePaint.setAntiAlias(true);

			float cellTextSize = cellHeight * 0.5f;

			datePaint.setTextSize(cellTextSize);

			datePaint.setTypeface(Typeface.DEFAULT_BOLD);

			boxPath = new Path();

			//boxPath.addRect(0, 0, width, height, Direction.CW);

			//boxPath.moveTo(0, monthHeight);

			boxPath.rLineTo(width, 0);

			boxPath.moveTo(0, monthHeight + weekHeight);

			boxPath.rLineTo(width, 0);

			for (int i = 1; i < 6; i++) {

				boxPath.moveTo(0, monthHeight + weekHeight + i * cellHeight);

				boxPath.rLineTo(width, 0);

				boxPath.moveTo(i * cellWidth, monthHeight);

				boxPath.rLineTo(0, height - monthHeight);

			}

			boxPath.moveTo(6 * cellWidth, monthHeight);

			boxPath.rLineTo(0, height - monthHeight);

			//preMonthBtnPath = new Path();

			//int btnHeight = (int) (monthHeight * 0.6f);

			//preMonthBtnPath.moveTo(monthChangeWidth / 2f, monthHeight / 2f);

			//preMonthBtnPath.rLineTo(btnHeight / 2f, -btnHeight / 2f);

			//preMonthBtnPath.rLineTo(0, btnHeight);

			//preMonthBtnPath.close();

			//nextMonthBtnPath = new Path();

			//nextMonthBtnPath.moveTo(width - monthChangeWidth / 2f,

			//		monthHeight / 2f);

			//nextMonthBtnPath.rLineTo(-btnHeight / 2f, -btnHeight / 2f);

			//nextMonthBtnPath.rLineTo(0, btnHeight);

			//nextMonthBtnPath.close();

			monthChangeBtnPaint = new Paint();

			monthChangeBtnPaint.setAntiAlias(true);

			monthChangeBtnPaint.setStyle(Paint.Style.FILL_AND_STROKE);

			monthChangeBtnPaint.setColor(btnColor);

			cellBgPaint = new Paint();

			cellBgPaint.setAntiAlias(true);

			cellBgPaint.setStyle(Paint.Style.FILL);

			cellBgPaint.setColor(cellSelectedColor);

		}

	}

}
    每日一道理
因为自信,在呀呀学语时,我靠着纤嫩的双腿,迈出人生的第一步;因为自信,我一次次将第一名的奖状高高举起;因为自信,我毫不吝惜地剪掉飘逸的长发,在运动场上展现风采……感谢自信,它给了我一双翅膀,让我在电闪雷鸣中去飞翔,在风雨中去搏击人生!

    实现日历控件:

<com.techrare.view.CalendarView

            android:id="@+id/calendar"

            android:layout_width="fill_parent"

            android:layout_height="fill_parent" />

    日历控件中的一些功能(可以自己加):

//获取日历控件对象

calendar = (CalendarView)findViewById(R.id.calendar);

//获取日历中年代 ya[0]为年,ya[1]为月(格式大家可以自行在日历控件中改)

String[] ya = calendar.getYearAndmonth().split("-"); 

//上一月 同样返回年代 

String leftYearAndmonth = calendar.clickLeftMonth(); 

String[] lya = leftYearAndmonth.split("-");

//下一月

String rightYearAndmonth = calendar.clickRightMonth(); 

String[] rya = rightYearAndmonth.split("-");

//设置控件监听,可以监听到点击的每一天(大家也可以在控件中自行设定)

calendar.setOnItemClickListener(new calendarItemClickListener());

class calendarItemClickListener implements OnItemClickListener{

	@Override

	public void OnItemClick(Date date) {

		Toast.makeText(getApplicationContext(), date+"", Toast.LENGTH_SHORT).show();

	}

 }

    这些功能只是配合项目中的需要来添加的,大家如有其他需求,可以自行在控件中添加,应该也不怎么困难!

    

    

文章结束给大家分享下程序员的一些笑话语录: 现在社会太数字化了,所以最好是有一个集很多功能于一身的设备!

你可能感兴趣的:(android)