Android实现签到日历控件

本文介绍如何在Android中实现一个签到日历控件,详细阐述了算法设计和程序实现过程,包括计算列序号、行序号的逻辑,以及绘制Mark、Cell Background和Cell的方法。通过自定义View和枚举类,实现了日期的垂直居中显示以及签到状态的交互功能。
摘要由CSDN通过智能技术生成

前言

最近在做公司的一个APP项目的时候,有一个需求是要做一个签到页面。笔者自己考虑了一下设计思路和算法,并且实现了一个可以签到的日历控件。

其实思路很简单,难点就在日期的绘制上。废话不多说,进入正题吧。

效果预览

效果预览


算法设计

总体思路设计

按照效果图中所示的绘制日历,把每一天当作一个处理对象,每一个处理对象都有一个行、列序号,只要能计算出相应的行列序号,那么绘制就不成问题了。

列序号相对比较容易算出来,比如2016年7月1日,是星期五,因此,7月1日就要画在星期五那个位置。也就是说,7月就是从第横向第5的位置开始的。行序号就要难一些了,不过不是不能实现,等我后边讲了基本原理之后,你就会发现这根本不是事。

计算列序号

根据Calendar类返回的值,星期日返回1,星期一开始返回2,一直到星期六返回7。这里应该做一个转换,从星期一到星期日,序号应该是从0到6,因此

ColumnIndex = (dayOfWeek == Calendar.DAY_OF_MONTH)? 6 : (dayOfWeek - 2);

计算行序号

计算行序号的核心目标是得出一个行序号计算通用公式,怎么得出这样一个公式呢。每一天绘制的位置要受当月第一天所“放置”的位置的影响,从另一个角度来看,就是跟当月第一周有几天有关系。这样的一个规律即可总结为一个通用公式。

我并不知道这样一个通用公式怎么得出来,可是试着猜想一下又有何不可呢。既然是要得到序号,序号当然是0、1、2这样比较小的数字,那么输入日期,输出序号,怎么办?那么就先把日期除以每周的天数7,把它变小吧。如果当月的第一天是星期一,那么计算结果如下图:

除以7结果

这样似乎就是我们需要的结果了,从1/7到1向上取整为1,就是第1行,以此类推,没什么问题,但这是个特例。如果当月第1天不是星期一呢?计算结果就不完全符合了,所以可以看出这个数值应该受当月第一周的天数影响。那么在除之前先减去第一周的天数如何?

减3除以7结果

这时候再看,从-2/7到0向上取整为0,1/7到1向上取整为1,这样岂不是非常正确了?事实也是如此,由此我们可以得出一个通用公式如下:

Weight = (dayOfMonth - daysOfFirstWeek)/MaxColumn

然后以求得的权重值,向上取整并求绝对值:

RowIndex = | ceil(Weight) |

肯定有人问,这里为什么还要求绝对值。这里的绝对值不是必须的,因为前面的-2/7在程序中向上取整的直接计算结果是-0,我想为了保险结果就取了绝对值。

如果你还不放心,那么我们再做一个验证,以2016年9月为例,第一周有4天:

日期 当月天数 权重值 行序号
9.1 1 -0.43 0
9.4 4 0 0
9.5 5 0.14 1
9.8 8 0.57 1
9.15 15 1.57 2
9.18 18 2 2

看,结果是不是还是我们预期的效果?


程序实现

先来看看我们要画一些什么:
1. 上面的星期标记,这里称为Mark。
2.

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值