有图有真像:




日历控件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);}@Overrideprotected 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);}@Overrideprotected 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);}@Overrideprotected 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 indexint 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,以星期一为开头-2curStartIndex = monthStart;date[monthStart] = 1;// last monthif (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 monthcalendar.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 monthfor (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 upif (downDate != null) {drawCellBg(canvas, downIndex, surface.cellDownColor);}// selected bg colorif (!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 downif (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();}@Overridepublic 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);}}}

实现日历控件:

                                                                


     



上一月图片:

调用 calendar.clickLeftMonth(); 
     

下一月:


调用 calendar.clickRightMonth(); 

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

//获取日历控件对象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{@Overridepublic void OnItemClick(Date date) {Toast.makeText(getApplicationContext(), date+"", Toast.LENGTH_SHORT).show();} }

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

 


点击我下载DEMO


更多相关文章

  1. Android(安卓)三角标签(自定义Textview控件)
  2. Android(安卓)ToggleButton控件的用法
  3. android 时间戳与日期格式的互相转换 以及 自定义选择器
  4. android 华为Mate 10 spinner 点击区域bug
  5. android简单的动态控制软键盘的显隐
  6. Android(安卓)时间 日期 时区
  7. Android中Adapter接口及其实现类详解
  8. 两种方式使用android时间和日期控件
  9. android动态生成控件

随机推荐

  1. Android(安卓)一些注意
  2. 避免在Android上冷启动
  3. 探索Android中的Parcel
  4. android 开发环境安装和测试中常出现的问
  5. Android读取JSON格式数据
  6. Android(安卓)Animation学习
  7. androidUI控件
  8. Android.PublishApplication
  9. Android(安卓)存储目录
  10. Android(安卓)ViewPager实现Tabhost选项