3) 月历操作函数:
/*
blf: calendar dayBeginIdx 和 dayCount图示
0 1 2 3 4 5 6 week section
---------------------------
1 rowIdx = 0
---------------------------
---------------------------
2 3 4 5 6 7 8 rowIdx = 1
---------------------------
---------------------------
9 10 11 12 13 14 15 rowIdx = 2
---------------------------
---------------------------
16 17 18 19 20 21 22 rowIdx = 3
---------------------------
---------------------------
23 24 24 25 26 27 28 rowIdx = 4
---------------------------
---------------------------
30 31 rowIdx = 5
---------------------------
*/
void calendar_set_year_month(SCalendar* calendar,int year,int month)
{
assert(calendar);
//if(calendar->date.year != year calendar->date.month != month)
{
calendar->date.year = year;
calendar->date.month = month;
//每个day设置为1号
calendar->date.day = 1;
//blf:
//参考上面图示,dayBeginIdx获得的是某个月1号相对日期区块中的索引,例如本例中1号索引为6
//而dayCount表示当前月的天数
//这样通过偏移与长度,我们可以很容易进行某些重要操作
//例如在碰撞检测某个cell是否被点中时,可以跳过没有日期的cell
//在绘图时检测某个cell是否找范围之外,如果之外就用灰色现实等等
//通过偏移量和count,进行范围判断
calendar->dayBeginIdx = date_get_week(&calendar->date);
calendar->dayCount = date_get_month_of_day(calendar->date.year, calendar->date.month);
}
}
void calendar_get_year_month(SCalendar* calendar,int* year,int* month)
{
assert(calendar);
if(year)
*year = calendar->date.year;
if(month)
*month = calendar->date.month;
}
/*
blf: 初始化一个月历结构,填充所有成员变量的数据
*/
void calendar_init(SCalendar* calendar,CGSize ownerSize,float yearMonthHeight,float weekHeight)
{
assert(calendar && calendar);
//memset(calendar, 0, sizeof(SCalendar));
calendar->size = ownerSize;
calendar->yearMonthSectionHeight = yearMonthHeight;
calendar->weekSectionHegiht = weekHeight;
//blf:daySectionHeight是计算出来的
calendar->daySectionHeight = ownerSize.height - yearMonthHeight - weekHeight;
//blf:错误检测,简单期间,全部使用assert在debug时候进行中断
assert(calendar->daySectionHeight > 0);
//blf:初始化时显示本地当前的年月日
//date_get_now(&calendar->date);
calendar_set_year_month(calendar, calendar->date.year, calendar->date.month);
}
/*
blf: 计算出年月区块的rect
*/
void calendar_get_year_month_section_rect(const SCalendar* calendar,CGRect* rect)
{
assert(rect);
memset(rect,0,sizeof(CGRect));
rect->size.width = calendar->size.width;
rect->size.height = calendar->yearMonthSectionHeight;
}
/*
blf: 计算出星期区块的rect
*/
void calendar_get_week_section_rect(const SCalendar* calendar,CGRect* rect)
{
assert(rect);
memset(rect,0,sizeof(CGRect));
rect->origin.y = calendar->yearMonthSectionHeight;
rect->size.width = calendar->size.width;
rect->size.height = calendar->weekSectionHegiht;
}
/*
blf: 计算出年日期区块的rect
*/
void calendar_get_day_section_rect(const SCalendar* calendar,CGRect* rect)
{
assert(calendar && rect);
memset(rect,0,sizeof(CGRect));
rect->origin.y = calendar->yearMonthSectionHeight + calendar->weekSectionHegiht;
rect->size.width = calendar->size.width;
rect->size.height = calendar->daySectionHeight;
}
/*
blf: 上面计算出来的是三大整体的区块(section)
下面计算出来的都是某个大区快中的子区(cell)
*/
/*
blf:
获取星期区块中每个索引指向的子区rect位置与尺寸
输出数据在rect参数中
---------------------------
0 1 2 3 4 5 6
---------------------------
idx = 0时表示星期日
用于绘图
*/
void calendar_get_week_cell_rect(const SCalendar* calendar,CGRect* rect,int idx)
{
assert(calendar && rect && idx >= 0 && idx < 7);
//获取星期区块
calendar_get_week_section_rect(calendar, rect);
//计算出cell的宽度
float cellWidth = rect->size.width / 7.0F;
//计算出x偏移量
rect->origin.x = cellWidth * idx;
rect->size.width = cellWidth;
}
/*
blf:
获取日期区块中行列索引指向的子区rect位置与尺寸
---------------------------
0 1 2 3 4 5 6 rowIdx = 0
---------------------------
---------------------------
0 1 2 3 4 5 6 rowIdx = 1
---------------------------
---------------------------
0 1 2 3 4 5 6 rowIdx = 2
---------------------------
---------------------------
0 1 2 3 4 5 6 rowIdx = 3
---------------------------
---------------------------
0 1 2 3 4 5 6 rowIdx = 4
---------------------------
---------------------------
0 1 2 3 4 5 6 rowIdx = 5
---------------------------
一个月总是在28--31天之间,由于星期要缩进,因此6行7列足够解决由于星期缩进引起的显示不全问题
用于绘图以及碰撞检测,共计42个单元格
以二维方式获取日期区块中索引指向的子区的rect位置与尺寸
*/
void calendar_get_day_cell_rect(const SCalendar* calendar,CGRect* rect,int rowIdx,int columIdx)
{
assert(calendar && rect && rowIdx >= 0 && rowIdx < 6 && columIdx >= 0 && columIdx < 7 );
float cellWidth = calendar->size.width / 7.0F;
float cellHeight = calendar->daySectionHeight / 6.0F;
rect->origin.x = cellWidth * columIdx;
rect->origin.y = cellHeight * rowIdx;
rect->size.width = cellWidth;
rect->size.height = cellHeight;
}
/*
blf:
以一维方式方式获取日期区块中索引指向的子区的rect位置与尺寸
*/
void calendar_get_day_cell_rect_by_index(const SCalendar* calendar,CGRect* rect,int idx)
{
assert(calendar && rect && idx >= 0 && idx < 42);
// (/ 和 %)符号的应用,用于计算出行列索引号
int rowIdx = (idx / 7);
int columIdx = (idx % 7);
calendar_get_day_cell_rect(calendar, rect, rowIdx, columIdx);
}
/*
blf:
检测touchPoint是否点击在日期区块的某一个cell中
如果检测到有cell被点中,返回索引
否则返回-1
0 1 2 3 4 5 6 week section
---------------------------
1 rowIdx = 0
---------------------------
---------------------------
2 3 4 5 6 7 8 rowIdx = 1
---------------------------
---------------------------
9 10 11 12 13 14 15 rowIdx = 2
---------------------------
---------------------------
16 17 18 19 20 21 22 rowIdx = 3
---------------------------
---------------------------
23 24 24 25 26 27 28 rowIdx = 4
---------------------------
---------------------------
30 31 rowIdx = 5
---------------------------
注意: 参数localPt是相对于你所继承的View的左上角[0,0]的偏移量,是定义在View空间坐标系的
*/
int calendar_get_hitted_day_cell_index(const SCalendar* calendar, CGPoint localPt)
{
//优化1: 如果一个点不在日期区块中,那么肯定没点中,立即返回
CGRect daySec;
calendar_get_day_section_rect(calendar, &daySec);
if(!CGRectContainsPoint(daySec,localPt))
return -1;
localPt.y -= daySec.origin.y;
//触摸点肯定会会点中日期区块中的某个cell
//优化2: 避免使用循环6*7次遍历整个cell,检测是否一点在该cell中,通过下面算法,可以立刻获得当前点所在的cell行列索引号
float cellWidth = daySec.size.width / 7.0F;
float cellHeight = daySec.size.height / 6.0F;
int columIdx = localPt.x / cellWidth;
int rowIdx = localPt.y / cellHeight;
//检测当前被点中的cell是否允许被选中,具体原理请参考
//函数void calendar_set_year_month(SCalendar* calendar,int year,int month)的注释
int idx = rowIdx * 7 + columIdx;
if(idx < calendar->dayBeginIdx idx > calendar->dayBeginIdx + calendar->dayCount - 1)
return -1;
//到此说明肯定有点中的cell,返回该cell的索引号
return idx;
}
第一部分完毕,下一篇我们关注ios的实现。
热门评论
再次修正一个bug,已上传github
-(void) setYearMonth:(int)year month:(int)month
{
calendar_set_year_month(&_calendar, year, month);
if (_calendar.date.month > 1) {
_lastMonthDayCount = date_get_month_of_day(_calendar.date.year,_calendar.date.month-1);
}else{
_lastMonthDayCount = date_get_month_of_day(_calendar.date.year-1,12);
}
[self setNeedsDisplay];
}
修正一个bug,已上传github
void date_map_index_to_year_month(SDate* to,int startYear,int idx)
{
assert(to);
to->year = startYear + idx / 12;
to->month = idx % 12 + 1;
//to->day = -1;
//修改成如下代码。应该为1而不是-1
to->day = 1;
}