继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一C)

jackyBu
关注TA
已关注
手记 22
粉丝 34
获赞 314

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的实现。

打开App,阅读手记
4人推荐
发表评论
随时随地看视频慕课网APP

热门评论

再次修正一个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;

}


查看全部评论