赞
踩
最近在做公司的一个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,把它变小吧。如果当月的第一天是星期一,那么计算结果如下图:
这样似乎就是我们需要的结果了,从1/7到1向上取整为1,就是第1行,以此类推,没什么问题,但这是个特例。如果当月第1天不是星期一呢?计算结果就不完全符合了,所以可以看出这个数值应该受当月第一周的天数影响。那么在除之前先减去第一周的天数如何?
这时候再看,从-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.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。