自定义日历控件,可以根据需求定制属于自己的日历


效果图

最近笔者的朋友需要写一个关于考勤的日历,效果如下,但在网上找了半天都找不到合适的,于是乎就向笔者求助,笔者本来觉得在晚上随便找个日历demo,然后随便的修改几下就可以完成,于是顺口答应,找来几个发现代码修改起来都比较麻烦,于是乎就想为何不自己写一个可以修改起来很方便的日历控件呢 ?那岂不是以后用起来也很方便么 ?于是乎笔者就动手写了一个日记控件,运行起来效果图如下,demo下载地址看完效果图我们就来谈一下笔者自己写自定义控件的思路
###自定义控件思路
笔者在写自定义控件的时候一般采用MVC模式,即是模型(model)-视图(view)-控制器(controller),首先我们分析一下model
####建立模型
建立模型之前,首先我们分析一下日历控件,以便于建立模型,先看图

我们把一个方框看做一个对象,要确定这个对象我们需要确定那些关键属性呢 ?

  1. 我们要知道这个对象在第几行第几列
  2. 我们要知道每个对象的宽和高,这样我们才可以确定一个对象的位置
  3. 这个对象包含的文字
  4. 其他还有背景类型,打卡类型等附加的属性,这样,一个对象就可以确定下来了。
    好了,那我们开始上代码,首先建立一个day的类
/*** 日期的类* Created by xiaozhu on 2016/8/7.*/
public class Day {/*** 单个日期格子的宽*/public int width;/*** 单个日期格子的高*/public int height;/*** 日期的文本*/public String text;/*** 文本字体的颜色*/public int textClor;/*** 日期背景的类型 0代表无任何背景,1代表正常打卡,2代表所选日期,3代表当前日期 4,代表即是当前日期,也被选中*/public int backgroundStyle;/*** 字体的大小*/public float textSize;/*** 背景的半径*/public int backgroundR;/*** 出勤的类型 0为不画,1为正常考勤,2为异常,3为出差外出灯*/public int workState;/*** 出勤状态的半径*/public int workStateR = 5;/*** 字体在第几行*/public int location_x;/*** 字体在第几列*/public int location_y;/*** 创建日期对象* @param width 每个日期格子的宽度* @param height 每个日期格子的高度*/public Day(int width, int height) {this.width = width;this.height = height;}

定义完我们所需要的属性之后再给day添加一个可以画自己的方法,这样一个完整的模型才算完成,画自己的方法如下

 /*** 画天数** @param canvas  要画的画布* @param paint   画笔* @param context 画布的上下文对象*/public void drawDays(Canvas canvas, Context context, Paint paint) {//取窄的边框为圆的半径backgroundR = width > height ? height : width;//画背景drawBackground(canvas, paint);//画数字drawTaxt(canvas, paint);//画考勤drawWorkState(canvas, paint);}/*** 画考勤** @param canvas* @param paint*/private void drawWorkState(Canvas canvas, Paint paint) {//确定圆心位置float cx = location_x * width + width / 2;float xy = location_y * height + height * 44 / 60;paint.setStyle(Paint.Style.FILL);//根据工作状态设置画笔颜色if (workState == 0) {return;}switch (workState) {case 1:paint.setColor(0xFF46CC6E);break;case 2:paint.setColor(0xFFF16269);break;case 3:paint.setColor(0xFF3E81ED);break;}canvas.drawCircle(cx, xy, workStateR, paint);}/*** 花数字** @param canvas* @param paint*/private void drawTaxt(Canvas canvas, Paint paint) {//根据圆的半径设置字体的大小textSize = backgroundR / 3;paint.setTextSize(textSize);paint.setColor(textClor);paint.setStyle(Paint.Style.FILL);//计算文字的宽度Rect rect = new Rect();paint.getTextBounds(text, 0, text.length(), rect);int w = rect.width();//计算画文字的位置float x = location_x * width + (width - w) / 2;float y = location_y * height + (height + textSize/2) / 2;canvas.drawText(text, x, y, paint);}/*** 画背景** @param canvas* @param paint*/private void drawBackground(Canvas canvas, Paint paint) {//画背景 根据背景状态设置画笔类型if (backgroundStyle == 0) {return;}switch (backgroundStyle) {case 1:paint.setColor(0xFFECF1F4);paint.setStyle(Paint.Style.FILL);break;case 2:paint.setStyle(Paint.Style.FILL);paint.setColor(0xFF457BF4);break;case 3:paint.setColor(0xFF457BF4);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(3);break;}//计算圆心的位置float cx = location_x * width + width / 2;float cy = location_y * height + height / 2;canvas.drawCircle(cx, cy, backgroundR * 9 / 20, paint);}

这样,一个完整的模型就建立完毕了
####建立控制类
我们现在建立一个控制的类,即DayManager类,并声明几个关键的参数

/*** 日期的管理类* Created by xiaozhu on 2016/8/7.*/
public class DayManager {/*** 记录当前的时间*/public static  String currentTime;/*** 当前的日期*/private static int current = -1;/*** 储存当前的日期*/private static int tempcurrent=-1;/****/static String[] weeks = {"日", "一", "二", "三", "四", "五", "六"};static String[] dayArray = {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15","16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"};

下面就是日起管理类的关键代码,即创建日期集合,并赋值的过程

  /*** 根据日历对象创建日期集合** @param calendar 根据日历生成月份数据,改变这个就可以改变月数* @param width 控件的宽度* @param heigh 控件的高度* @return 返回的天数的集合*/public static List<Day> createDayByCalendar(Calendar calendar, int width, int heigh) {//初始化休息的天数initRestDays(calendar);//模拟数据 ,无关紧要,imitateData();List<Day> days = new ArrayList<>();Day day = null;int dayWidth = width / 7;int dayHeight = heigh / (calendar.getActualMaximum(Calendar.WEEK_OF_MONTH) + 1);//添加星期对象,里面储存的分别是,日、一、二、三、四、五、六,for (int i = 0; i < 7; i++) {day = new Day(dayWidth, dayHeight);//为星期设置位置,为第0行,day.location_x = i;day.location_y = 0;day.text = weeks[i];//设置日期颜色day.textClor = 0xFF699CF0;days.add(day);}int count = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);calendar.set(Calendar.DAY_OF_MONTH, 1);int firstWeekCount = calendar.getActualMaximum(Calendar.DAY_OF_WEEK);//生成每一天的对象,其中第i次创建的是第i+1天for (int i = 0; i < count; i++) {day = new Day(dayWidth, dayHeight);day.text = dayArray[i];calendar.set(Calendar.DAY_OF_MONTH, i + 1);//设置每个天数的位置,即在表格的第几行第几列day.location_y = calendar.get(Calendar.WEEK_OF_MONTH);day.location_x = calendar.get(Calendar.DAY_OF_WEEK) - 1;//设置日期选择状态if (i == current - 1) {day.backgroundStyle = 3;day.textClor = 0xFF4384ED;} else if (i == select - 1) {day.backgroundStyle = 2;day.textClor = 0xFFFAFBFE;} else {day.backgroundStyle = 1;day.textClor = 0xFF8696A5;}//设置工作状态if (restDays.contains(1 + i)) {day.workState = 0;} else if (abnormalDays.contains(i + 1)) {day.workState = 2;} else if (outDays.contains(i + 1)) {day.workState = 3;} else {day.workState = 1;}days.add(day);}return days;}/*** 模拟数据*/private static void imitateData() {abnormalDays.add(2);abnormalDays.add(11);abnormalDays.add(16);abnormalDays.add(17);abnormalDays.add(23);outDays.add(8);outDays.add(9);outDays.add(18);outDays.add(22);}/*** 初始化休息的天数  计算休息的天数** @param calendar*/private static void initRestDays(Calendar calendar) {int total = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);for (int i = 0; i < total; i++) {calendar.set(Calendar.DAY_OF_MONTH, i + 1);if (calendar.get(Calendar.DAY_OF_WEEK) == 1 || calendar.get(Calendar.DAY_OF_WEEK) == 7) {restDays.add(i + 1);}}}

好了,一个日期控制类就完成了
####建立view类,对日期进行显示
我们现在建立一个CalendarView类,并让他继承View类,并重写onDraw方法。

/*** 自定义的日历控件* Created by xiaozhu on 2016/8/1.*/
public class CalendarView extends View {private Context context;/*** 画笔*/private Paint paint;/**** 当前的时间*/private Calendar calendar;@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//获取day集合并绘制List<Day> days = DayManager.createDayByCalendar(calendar, getMeasuredWidth(), getMeasuredHeight());for (Day day : days) {day.drawDays(canvas, context, paint);}}

我们在onDraw里面调用DayManager的createDayByCalendar方法,并把当前控件显示的日历和控件的宽高传进去,获取日期的集合,遍历集合,调用对象的drawDays方法,把画笔和画布穿进去,一个完整的日历就画出来了。最后我们对他进行完善,即添加点击响应事件。下面我们重写onTouchEvent方法

 @Overridepublic boolean onTouchEvent(MotionEvent event) {if (MotionEvent.ACTION_DOWN == event.getAction()) {//判断点击的是哪个日期float x = event.getX();float y = event.getY();//计算点击的是哪个日期int locationX = (int) (x * 7 / getMeasuredWidth());int locationY = (int) ((calendar.getActualMaximum(Calendar.WEEK_OF_MONTH) + 1) * y / getMeasuredHeight());if (locationY == 0) {return super.onTouchEvent(event);} else if (locationY == 1) {calendar.set(Calendar.DAY_OF_MONTH, 1);System.out.println("xiaozhu" + calendar.get(Calendar.DAY_OF_WEEK) + ":" + locationX);if (locationX < calendar.get(Calendar.DAY_OF_WEEK) - 1) {return super.onTouchEvent(event);}} else if (locationY == calendar.getActualMaximum(Calendar.WEEK_OF_MONTH)) {calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));if (locationX > calendar.get(Calendar.DAY_OF_WEEK) + 1) {return super.onTouchEvent(event);}}calendar.set(Calendar.WEEK_OF_MONTH, (int) locationY);calendar.set(Calendar.DAY_OF_WEEK, (int) (locationX + 1));DayManager.setSelect(calendar.get(Calendar.DAY_OF_MONTH));//添加点击监听if (listener!=null){listener.selectChange(this,calendar.getTime());}invalidate();}return super.onTouchEvent(event);}

好了,一个完整的日历控件就画完了。
####在activity里面使用
创建布局文件,在布局文件添加控件,然后再给控件添加月份标题

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="300dp"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.calendar.MainActivity"><RelativeLayoutandroid:padding="10dp"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:clickable="true"android:id="@+id/tv_pre"android:textColor="#4586ED"android:layout_centerVertical="true"android:textSize="16sp"android:text="7月"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:layout_centerInParent="true"android:id="@+id/tv_month"android:textColor="#768797"android:layout_centerVertical="true"android:textSize="16sp"android:text="2016年8月"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:clickable="true"android:layout_alignParentRight="true"android:id="@+id/tv_next"android:textColor="#4586ED"android:layout_centerVertical="true"android:textSize="16sp"android:text="8月"android:layout_width="wrap_content"android:layout_height="wrap_content" /></RelativeLayout><com.example.calendar.view.CalendarViewandroid:id="@+id/calendar"android:layout_width="300dp"android:layout_height="300dp" />
</LinearLayout>

在activity里面查找到控件,并通过CaldendarView里面的setCalendar方法来显示calendar代表的月份。
###更改自己想要的视图
####更改统一样式
如果我们想要更改所有布局的样式,只需要给CalendarView设置回调即可,在方法里面画上自己需要的东西。
,我们需要用到的几个属性是

  1. width 单个对象的宽度
  2. height 单个对象的高度

然后我们就可以确定我们绘图的区域即(0,0 )为区域左上角坐标,(width,height )为右下角坐标,可以在此区域画上任何你想添加的东西,而width ,height ,都是通过DayManager在控制,完全不用你去考虑

####更改特殊样式
如果你想给某一天添加特殊的属性,请参照使用引导
使用引导

自定义日历控件,可以根据需求定制属于自己的日历相关推荐

  1. 可编辑的日历控件_选择正确的WordPress编辑日历插件

    可编辑的日历控件 什么是编辑日历? (What is an Editorial Calendar?) An editorial calendar is the foundation of strate ...

  2. android高德地图上加自定义菜单,自定义UI控件-UI界面定制-开发指南-Android 导航SDK | 高德地图API...

    关于自定义 UI 布局,您还可以参考官方Demo--完全自定义UI导航. 单元素自定义 可以通过AMapNaviViewOptions中如下接口进行单UI元素显示隐藏,只列出部分接口,更多功能请参考A ...

  3. calendar控件使用 extjs_ExtJs定制日历控件——自动加载更新(日历控件显示)

    将定制的日历控件放到一个Panel里显示,其结构如下: , { border: true, id: 'page', animCollapse : true, width: 1050, height: ...

  4. 带你开发一个日历控件

    首发我的博客 - https://blog.cdswyda.com/post/2017121010 日历控件多的不胜枚举,为什么我们还要再造一个轮子呢? 因为大多数日历控件都是用于选择日期的,有种需求 ...

  5. WPF 4 日历控件(Calendar)

    WPF 4 日历控件(Calendar) 原文:WPF 4 日历控件(Calendar) 在之前我已经写过两篇关于WPF 4 任务栏(Taskbar)相关的特性.相信自从VS2010 Beta 版放出 ...

  6. pythongui日历控件_“五一”快到了,用Python中PyQt5做一个日历,QCalendar控件详解...

    前面内容,我们详细了解了PyQt5中的一些常用控件 精彩内容回顾 Python用PyQt5设计界面,如何正确显示一幅图片,QPixmap控件详解 拥有漂亮的笔刷才能绘制多彩界面,PythonPyQt5 ...

  7. JavaScript blog式日历控件javascript

    javascript blog式日历控件 近来要做一个记事本系统,想找一个合适的日历控件,但网上的都是那种日历选择控件. 于是到qq的记事本系统找了一个,但里面的算法有点落后,所以用了它的样式自己写了 ...

  8. Excel 2007中日历控件使用(文字)

    在Excel中插入日历控件 1.在某一单元格中插入日历控件 (1)选中要插入日历控件的单元格,设置单元格格式为日期型: (2)点击工具栏,"插入-对象-日历控件", (3)用快捷方 ...

  9. 安卓学习笔记--- Android自定义View(CustomCalendar-定制日历控件)

    最近需要做一个日历的控件,感觉使用系统的不能满足自己需求,发现了一个比较不错的自定义日历控件,博主写的很好,转载支持一下. 转载地址: http://blog.csdn.net/xmxkf/artic ...

最新文章

  1. OpenResty 概要及原理科普
  2. 【安全技术】红队之windows信息收集思路
  3. 计划策略-20-订货型生产
  4. android手机连接无线路由器上网设置,怎样用手机设置无线路由器上网?
  5. http --- 基本认证与摘要认证
  6. [vue] 在子组件中怎么访问到父组件的实例?
  7. linux ACL应用学习
  8. python+flask搭建CNN在线识别手写中文网站
  9. 使用驱动器h中的光盘之前需要将其格式化怎么办_电脑磁盘显示未分配怎么办?磁盘数据如何恢复?...
  10. 【我的相册】2018.2.15-年夜饭
  11. php提示返回,PHP指定方法的返回类型提示
  12. C++小游戏——迷宫
  13. OpenCV实战2——进行颜色检测(HSV颜色空间)和分割的隐形斗篷
  14. 【4.29】Codeforces 刷题
  15. 针对谷氨酰胺运输体的小分子抑制剂
  16. matlab求hession矩阵
  17. 台湾大学郭彦甫matlab百度云,台湾国立大学郭彦甫Matlab教程笔记(23) linear systems...
  18. 天空之城 10孔口琴
  19. 【JavaScript】性能优化
  20. 微信小程序学习记录(一)小实战——加法计算器

热门文章

  1. 关于Membership 类
  2. 深入理解Kafka必知必会(1)
  3. 4.3寸TFTLCD之NT35510关键指令解析
  4. 线性 - 比较器LM339APWR 电子元器件采购
  5. Python视频学习(十二、Django)
  6. 怎样在WPS上实现代码语法高亮(转)
  7. 电脑回收站被清理删除了 怎么恢复回收站的数据?
  8. android壁纸软件代码,Flutter开源项目——Android免费壁纸应用
  9. PS游戏摸拟器ePSXe加速游戏速度方法
  10. compare函数c语言,sort(compare)方法