标签:
本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu
前言
章节:
1、需求描述以及c/c++实现日期和月历的基本操作
2、ios实现自绘日期选择控件
3、android实现自绘日期选择控件
目的:
通过一个相对复杂的自定义自绘控件来分享:
1、ios以及android自定义自绘控件的开发流程
2、objc与c/c++混合编程
3、android ndk的环境配置,android studio ndk的编译模式,swig在android ndk开发中的作用
一、需求描述以及c/c++实现日期和月历的基本操作
1、需求描述:
图1 某个月的日历外观 图2 日期区间选中状态
1) 该日期选择控件主要用于日期过滤查询,一般用于近n年的数据查询。
2) 假设你点击某个按钮弹出该日期选择控件时,自动定位到当前月,例如本月是4月,则4月份显示在屏幕最下方。
3) 当你手指向上滑动时,向前n个月滚动(月份例如:4-3-2-1),手指向下滑动时,向后n个月滚动(月份例如:1-2-3-4)。
4) 日期区分为可选择区或不可选择区(图1),当你第一次点击可选的日期,该日期会被选中(蓝色)。
5) 当你第二次点击可选的日期,则会形成一个选区(图2),该选区会跳过所有不可选的日期。
2、为什么使用c/c++:
1) 历史原因:该控件是两年前为某个项目实现的,当时没有移动开发经验,因此最初技术预研时选择了跨平台的cocos2d-x来开发,并为其实现了该控件.但是cocos2d-x存在一些bug,并且其基于游戏开发模式,不停的循环绘制,cpu占用高,耗电量大。如果要用cocos2d-x开发一般的app的话,需要为其加入脏区局部刷新的功能,这样改动量太大。在研究cocos2d-x时,其所见即所得的cocostudio需要使用swig将c/c++代码wrap成c#供其进行平台调用。当时觉得swig真是强大无比,可以自动wrap为c#,java,python,lua,js....等进行相互调用。
2) ios端objc可以非常容易的与c/c++进行相互调用,而android ndk+swig也可以大大减轻c/c++代码在android端的实现和调用难度(具体我们在第三部分中可以体会到)。这样我们就能够重用为cocos2d-x所写的c/c++代码。
3) 基于java的android程序,非常容易进行反编译,因此使用c/c++编译成.so后,都是二进制代码。因此如果对运行速度或代码安全性有比较高的要求的话,可以使用c/c++进行实现,由android java jni进行调用。
4) 还有一个重要原因就是想深入了解一下android ndk以及swig的开发方式。
3、为什么选择自定义自绘控件方式:
不管是android还是ios,自定义控件的实现基本上有三种方式:
1) 利用androidStudio或xcode interfaceBuilder中的容器控件以及其他控件组合拼装而成,自定义控件不需要继承自View或子类。你可以进行一些事件的编写就可以完成很多需求。
2) 继承自View或子类,再用现有的控件组合拼装而成。
3) 继承自View或子类,所有该自定义View的显示效果由我们来绘制出来。
这里我们采取第三种方式。相对来说,这种方式内存消耗要小很多,并且速度上也有一定优势吧。要知道每个月都是需要42个cell表示日期,并且加上年月和星期这些区块,都用View组合而成,内存也不算小。不管是ios还是android,每个View的成员变量都不少。而使用自绘控件,只要一个View就解决了。至少内存使用上可以减少40多个View的使用,对吧?
4、c/c++实现细节:
1) android中的一些适配结构和函数:
因为使用了ios内置的例如CGRect,CGPoint,CGSize等c语言结构,而android ndk中没有这些结构,因此对于android来说,需要实现这些结构以及在整个程序中用到的一些函数。c/c++中要做到这些,可以使用宏来判断和切换当前的环境,具体见代码:
1 /* 2 blf: 使用ios中的一些基础数据结构,android中需要移植过来 3 ios的话,请将下面 #define ANDROID_NDK_IMP这句代码注释掉 4 */ 5 #define ANDROID_NDK_IMP 6 #ifdef ANDROID_NDK_IMP 7 typedef struct _CGPoint { 8 float x; 9 float y; 10 }CGPoint; 11 12 /* Sizes. */ 13 typedef struct _CGSize { 14 float width; 15 float height; 16 }CGSize; 17 18 /* Rectangles. */ 19 typedef struct _CGRect { 20 CGPoint origin; 21 CGSize size; 22 }CGRect; 23 #endif
1 /* 2 blf: 使用ios中的一些基础数据结构,android中需要移植过来 3 下面是实现代码 4 */ 5 #ifdef ANDROID_NDK_IMP 6 static float GetRectMaxX(CGRect rc) { return rc.origin.x + rc.size.width; } 7 static float GetRectMaxY(CGRect rc) { return rc.origin.y + rc.size.height; } 8 static bool CGRectContainsPoint(CGRect rc, CGPoint pt) 9 { 10 return(pt.x >= rc.origin.x) && (pt.x <= GetRectMaxX(rc)) && (pt.y >= rc.origin.y) && (pt.y <= GetRectMaxY(rc)); 11 } 12 #endif
2) 日期操作函数:
这些函数都和日期操作相关,具体请参考代码,注释应该比较清楚的。
1 /* 2 blf: 函数参数都是以指针方式传入(java或c#中就为传引用,swig将指针会转换为类对象,所有类对象在java和c#中都是传引用的. 3 c#支持struct,是值类型 4 5 c#还支持参数的ref和out方式,可以将值类型以传引用方式输出到参数中,相当于c中的指针 6 7 经验之谈:除非在c/c++中你使用shared_ptr等智能指针,否则千万不要在函数或成员方法中malloc或new一个新对象然后return出来。 8 比较好的方式还是通过参数传指针或引用方式来返回更新的数据。 9 */ 10 void date_set(SDate* ret,int year,int month,int day) 11 { 12 assert(ret); 13 ret->year = year; 14 ret->month = month; 15 ret->day = day; 16 } 17 18 /* 19 blf: 获取当前的年月日 20 */ 21 void date_get_now(SDate* ret) 22 { 23 assert(ret); 24 25 //time()此函数会返回从公元 1970 年1 月1 日的UTC 时间从0 时0 分0 秒算起到现在所经过的秒数。 26 //记住:是秒数,而不是毫秒数(很多语言返回的是毫秒数,crt中是以秒为单位的) 27 //如果t 并非空指针的话,此函数也会将返回值存到t指针所指的内存 28 time_t t; 29 time(&t); 30 31 //转换到当前系统的本地时间 32 struct tm* timeInfo; 33 timeInfo = localtime(&t); 34 35 //tm结构中的年份是从1900开始到今天的年数,因此需要加上1900 36 ret->year = timeInfo->tm_year + 1900; 37 38 //月份是 0 base的,我们按照1-12的方式来计算,因此加1 39 ret->month = timeInfo->tm_mon + 1; 40 41 ret->day = timeInfo->tm_mday; 42 } 43 44 /* 45 blf: 是否相等 46 */ 47 bool date_is_equal(const SDate* left,const SDate* right) 48 { 49 assert(left&&right); 50 return (left->year == right->year && 51 left->month == right->month && 52 left->day == right->day); 53 } 54 55 /* 56 blf: 计算两个年份之间的月数 57 */ 58 int date_get_month_count_from_year_range(int startYear,int endYear) 59 { 60 int diff = endYear - startYear + 1; 61 return diff * 12; 62 } 63 64 /* 65 blf: 将一维的数据表示映射成二维表示(年和月) 66 startYear表示起始年,例如 2010年 67 idx表示相对2010年开始的月份偏移量 68 69 我们会在下面和后面代码中看到/ 和 %的多次使用 70 可以理解为,将一维数据映射成二维行列表示的数据时,都可以使用这种方式 71 72 下面这个函数用于月历区间选择控件,例如你有个数据库查询需求,可以查询 73 当前年月日----五年前的年1月1号之间的数据,此时在UITabelView或ListView时,就需要 74 调用本函数来显示年月信息等 75 */ 76 void date_map_index_to_year_month(SDate* to,int startYear,int idx) 77 { 78 assert(to); 79 80 //每年有12个月,idx/12你可以看成每12个月进一位,加上startYear基准值,就可以获得当前年份 81 to->year = startYear + idx / 12; 82 83 //每年有12个月,idx%12你可以看成【0-11】之间循环,加1是因为我们的SDate结构是1-12表示的 84 to->month = idx % 12 + 1; 85 86 //至于day,这里为-1,我们在map中忽略该值,可以设置任意值 87 to->day = -1; 88 } 89 90 /* 91 blf: 下面函数来源于linux实现,计算从某个时间点(年月日时分秒)到1970年0时0分0秒的时间差 92 参考url: http://blog.csdn.net/axx1611/article/details/1792827 93 */ 94 long mymktime (unsigned int year, unsigned int mon, 95 unsigned int day, unsigned int hour, 96 unsigned int min, unsigned int sec) 97 { 98 if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ 99 mon += 12; /* Puts Feb last since it has leap day */ 100 year -= 1; 101 } 102 103 return ((( 104 (long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + 105 year*365 - 719499 106 )*24 + hour /* now have hours */ 107 )*60 + min /* now have minutes */ 108 )*60 + sec; /* finally seconds */ 109 } 110 111 /* 112 blf: 下面函数一共实现了三个版本 113 114 第一版: 不知道是我对c的mktime用法错误还是有bug(理论上不可能,因为ios和android中都存在问题) 115 同一个时间点,例如2016年1月1日0时0分1秒与1970年1月1日0时0分0秒的时间差不一样。 116 117 第二版: 使用ios自身的 NSCalendar对象计算时间差,这个计算是正确的,但是只能用在ios中 118 119 第三版: http://blog.csdn.net/axx1611/article/details/1792827中的算法,来自于linux源码,ios/android中运行的很好 120 121 为什么不用time_t而是使用long呢? 122 这是因为android中使用swig将c/c++ 代码转换成java jni封装的函数时,time_t被封装成了对象。 123 因为java不认识c的typedef结构,Swig将其转换为SWITGYPT_p_XXXXX类型的包装(经典的装箱/拆箱,每次操作都要进行装箱拆箱,很麻烦). 124 time_t只是64位整型的typedef而已,因此转换为long后,经Swig转换后,对应为java的整型,这样操作起来比较简单 125 126 */ 127 128 long date_get_time_t(const SDate* d) 129 { 130 assert(d); 131 132 /* 133 1、第一版 134 struct tm date; 135 //crt函数中year是基于1900年的偏移,因此要减去1900 136 date.tm_year = d->year - 1900; 137 138 //crt函数中月份是[0-11]表示的,我们使用[1-12]表示,因此要减去1 139 date.tm_mon = d->month - 1; 140 141 date.tm_mday = d->day; 142 date.tm_hour = 0; 143 date.tm_min = 0; 144 date.tm_sec = 1; 145 time_t seconds = mktime(&date); 146 147 return (long)seconds; 148 */ 149 150 /* 151 2、第二版 ios NSCalendar对象计算时间差 152 NSDateComponents *components = [[NSDateComponents alloc] init]; 153 154 [components setDay:d->day]; // Monday 155 [components setMonth:d->month]; // May 156 [components setYear:d->year]; 157 158 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 159 160 NSDate *date = [gregorian dateFromComponents:components]; 161 162 return (time_t) [date timeIntervalSince1970]; 163 */ 164 165 /* 166 3、网上Linux版本 167 */ 168 return mymktime(d->year,d->month,d->day,0,0,1); 169 } 170 171 /* 172 blf: 根据delta计算月份,返回值存储在date结构中 173 例如:当前年月为2015年1月份,delta为2,则返回2014年11月 174 */ 175 void date_get_prev_month(SDate* date, int delta) 176 { 177 assert(date); 178 179 if((date->month - delta) < 1) 180 { 181 //条件: 假设为2015年1月,delta = 2 182 //因为: 1-2 = -1 < 1 183 //所以: 年数 = 2015 - 1 = 2014 月份 = 12 + 1 - 2 = 11 184 date->year--; 185 date->month = 12 + date->month - delta; 186 } 187 else 188 date->month = date->month - delta; 189 } 190 191 /* 192 blf: 根据delta计算出月份,返回值存储在date结构中 193 例如:当前年月为2015年11月份,delta为2,则返回2016年1月 194 */ 195 void date_get_next_month(SDate* date, int delta) 196 { 197 assert(date); 198 if((date->month + delta) > 12) 199 { 200 //条件: 假设为2015年11月,delta = 2 201 //因为: 11 + 2 = 13 > 12 202 //所以: 年数 = 2015 + 1 = 2016 月份 = 11 + 2 - 12 = 1 203 date->year++; 204 date->month = date->month + delta - 12; 205 } 206 else 207 date->month = date->month + delta; 208 } 209 210 /* 211 blf: 根据输入年份,判断是否是闰年 212 固定算法:判断闰年的方法是该年能被4整除并且不能被100整除,或者是可以被400整除 213 */ 214 int date_get_leap(int year) 215 { 216 if(((year % 4 == 0) && (year % 100) != 0) || (year % 400 == 0)) 217 return 1; 218 return 0; 219 } 220 221 /* 222 blf: 辅助函数,用于计算某年某月的某天是星期几 223 */ 224 int date_get_days(const SDate* date) 225 { 226 assert(date); 227 int day_table[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; 228 int i = 0, total = 0; 229 for(i = 0; i < date->month; i++) 230 total += day_table[i]; 231 return total + date->day + date_get_leap(date->year); 232 } 233 234 /* 235 blf: 用于计算某年某月的某天是星期几,调用上面函数 236 这些算法比较固定,具体原理也不需要太了解,因为我也不清楚。 237 */ 238 int date_get_week(const SDate* date) 239 { 240 assert(date); 241 return ((date->year - 1 + (date->year - 1) / 4 - (date->year - 1) / 100 + 242 (date->year - 1) / 400 + date_get_days(date) )% 7); 243 } 244 245 /* 246 blf: 用于计算某个月的天数 247 */ 248 int date_get_month_of_day(int year, int month) 249 { 250 switch(month) 251 { 252 case 1: 253 case 3: 254 case 5: 255 case 7: 256 case 8: 257 case 10: 258 case 12: return 31; 259 case 4: 260 case 6: 261 case 9: 262 case 11: return 30; 263 } 264 //blf:2月比较特别,要进行闰年判断 265 return 28 + date_get_leap(year); 266 }
3) 月历操作函数:
1 typedef struct _calendar 2 { 3 CGSize size; //大小尺寸 4 SDate date; //该月历代表的年月 5 6 float yearMonthSectionHeight; //年月区块的高度 7 float weekSectionHegiht; //星期区块的高度 8 9 //blf:计算出来的结果,第三方不要设置这些变量 10 float daySectionHeight; //已知size.height以及yearMonthSectionHeight和weekSectionHegiht,就能计算出日期区块的高度 11 12 int dayBeginIdx; //1号的偏移索引,具体描述参考实现代码 13 int dayCount; //当前月份一共多少天 14 15 }SCalendar;
1 /* 2 blf: calendar dayBeginIdx 和 dayCount图示 3 4 0 1 2 3 4 5 6 week section 5 --------------------------- 6 | | | | | | | 1 | rowIdx = 0 7 --------------------------- 8 --------------------------- 9 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | rowIdx = 1 10 --------------------------- 11 --------------------------- 12 | 9 | 10| 11| 12| 13| 14| 15| rowIdx = 2 13 --------------------------- 14 --------------------------- 15 | 16| 17| 18| 19| 20| 21| 22| rowIdx = 3 16 --------------------------- 17 --------------------------- 18 | 23| 24| 24| 25| 26| 27| 28| rowIdx = 4 19 --------------------------- 20 --------------------------- 21 | 30| 31| | | | | | rowIdx = 5 22 --------------------------- 23 24 */ 25 26 void calendar_set_year_month(SCalendar* calendar,int year,int month) 27 { 28 assert(calendar); 29 //if(calendar->date.year != year || calendar->date.month != month) 30 { 31 calendar->date.year = year; 32 calendar->date.month = month; 33 //每个day设置为1号 34 calendar->date.day = 1; 35 36 //blf: 37 //参考上面图示,dayBeginIdx获得的是某个月1号相对日期区块中的索引,例如本例中1号索引为6 38 //而dayCount表示当前月的天数 39 //这样通过偏移与长度,我们可以很容易进行某些重要操作 40 //例如在碰撞检测某个cell是否被点中时,可以跳过没有日期的cell 41 //在绘图时检测某个cell是否找范围之外,如果之外就用灰色现实等等 42 //通过偏移量和count,进行范围判断 43 calendar->dayBeginIdx = date_get_week(&calendar->date); 44 calendar->dayCount = date_get_month_of_day(calendar->date.year, calendar->date.month); 45 } 46 47 } 48 49 void calendar_get_year_month(SCalendar* calendar,int* year,int* month) 50 { 51 assert(calendar); 52 if(year) 53 *year = calendar->date.year; 54 if(month) 55 *month = calendar->date.month; 56 } 57 58 /* 59 blf: 初始化一个月历结构,填充所有成员变量的数据 60 */ 61 void calendar_init(SCalendar* calendar,CGSize ownerSize,float yearMonthHeight,float weekHeight) 62 { 63 assert(calendar && calendar); 64 65 //memset(calendar, 0, sizeof(SCalendar)); 66 67 calendar->size = ownerSize; 68 calendar->yearMonthSectionHeight = yearMonthHeight; 69 calendar->weekSectionHegiht = weekHeight; 70 //blf:daySectionHeight是计算出来的 71 calendar->daySectionHeight = ownerSize.height - yearMonthHeight - weekHeight; 72 //blf:错误检测,简单期间,全部使用assert在debug时候进行中断 73 assert(calendar->daySectionHeight > 0); 74 75 //blf:初始化时显示本地当前的年月日 76 //date_get_now(&calendar->date); 77 78 calendar_set_year_month(calendar, calendar->date.year, calendar->date.month); 79 } 80 81 /* 82 blf: 计算出年月区块的rect 83 */ 84 void calendar_get_year_month_section_rect(const SCalendar* calendar,CGRect* rect) 85 { 86 assert(rect); 87 memset(rect,0,sizeof(CGRect)); 88 rect->size.width = calendar->size.width; 89 rect->size.height = calendar->yearMonthSectionHeight; 90 } 91 92 /* 93 blf: 计算出星期区块的rect 94 */ 95 void calendar_get_week_section_rect(const SCalendar* calendar,CGRect* rect) 96 { 97 assert(rect); 98 memset(rect,0,sizeof(CGRect)); 99 rect->origin.y = calendar->yearMonthSectionHeight; 100 rect->size.width = calendar->size.width; 101 rect->size.height = calendar->weekSectionHegiht; 102 } 103 104 /* 105 blf: 计算出年日期区块的rect 106 */ 107 void calendar_get_day_section_rect(const SCalendar* calendar,CGRect* rect) 108 { 109 assert(calendar && rect); 110 memset(rect,0,sizeof(CGRect)); 111 rect->origin.y = calendar->yearMonthSectionHeight + calendar->weekSectionHegiht; 112 rect->size.width = calendar->size.width; 113 rect->size.height = calendar->daySectionHeight; 114 } 115 116 /* 117 blf: 上面计算出来的是三大整体的区块(section) 118 下面计算出来的都是某个大区快中的子区(cell) 119 */ 120 121 /* 122 blf: 123 获取星期区块中每个索引指向的子区rect位置与尺寸 124 输出数据在rect参数中 125 --------------------------- 126 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 127 --------------------------- 128 idx = 0时表示星期日 129 用于绘图 130 */ 131 132 void calendar_get_week_cell_rect(const SCalendar* calendar,CGRect* rect,int idx) 133 { 134 assert(calendar && rect && idx >= 0 && idx < 7); 135 //获取星期区块 136 calendar_get_week_section_rect(calendar, rect); 137 //计算出cell的宽度 138 float cellWidth = rect->size.width / 7.0F; 139 //计算出x偏移量 140 rect->origin.x = cellWidth * idx; 141 rect->size.width = cellWidth; 142 } 143 144 145 /* 146 blf: 147 获取日期区块中行列索引指向的子区rect位置与尺寸 148 --------------------------- 149 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | rowIdx = 0 150 --------------------------- 151 --------------------------- 152 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | rowIdx = 1 153 --------------------------- 154 --------------------------- 155 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | rowIdx = 2 156 --------------------------- 157 --------------------------- 158 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | rowIdx = 3 159 --------------------------- 160 --------------------------- 161 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | rowIdx = 4 162 --------------------------- 163 --------------------------- 164 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | rowIdx = 5 165 --------------------------- 166 167 一个月总是在28--31天之间,由于星期要缩进,因此6行7列足够解决由于星期缩进引起的显示不全问题 168 用于绘图以及碰撞检测,共计42个单元格 169 170 以二维方式获取日期区块中索引指向的子区的rect位置与尺寸 171 */ 172 173 void calendar_get_day_cell_rect(const SCalendar* calendar,CGRect* rect,int rowIdx,int columIdx) 174 { 175 assert(calendar && rect && rowIdx >= 0 && rowIdx < 6 && columIdx >= 0 && columIdx < 7 ); 176 float cellWidth = calendar->size.width / 7.0F; 177 float cellHeight = calendar->daySectionHeight / 6.0F; 178 rect->origin.x = cellWidth * columIdx; 179 rect->origin.y = cellHeight * rowIdx; 180 rect->size.width = cellWidth; 181 rect->size.height = cellHeight; 182 } 183 184 /* 185 blf: 186 以一维方式方式获取日期区块中索引指向的子区的rect位置与尺寸 187 */ 188 void calendar_get_day_cell_rect_by_index(const SCalendar* calendar,CGRect* rect,int idx) 189 { 190 assert(calendar && rect && idx >= 0 && idx < 42); 191 // (/ 和 %)符号的应用,用于计算出行列索引号 192 int rowIdx = (idx / 7); 193 int columIdx = (idx % 7); 194 calendar_get_day_cell_rect(calendar, rect, rowIdx, columIdx); 195 196 } 197 198 /* 199 blf: 200 检测touchPoint是否点击在日期区块的某一个cell中 201 如果检测到有cell被点中,返回索引 202 否则返回-1 203 204 0 1 2 3 4 5 6 week section 205 --------------------------- 206 | | | | | | | 1 | rowIdx = 0 207 --------------------------- 208 --------------------------- 209 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | rowIdx = 1 210 --------------------------- 211 --------------------------- 212 | 9 | 10| 11| 12| 13| 14| 15| rowIdx = 2 213 --------------------------- 214 --------------------------- 215 | 16| 17| 18| 19| 20| 21| 22| rowIdx = 3 216 --------------------------- 217 --------------------------- 218 | 23| 24| 24| 25| 26| 27| 28| rowIdx = 4 219 --------------------------- 220 --------------------------- 221 | 30| 31| | | | | | rowIdx = 5 222 --------------------------- 223 注意: 参数localPt是相对于你所继承的View的左上角[0,0]的偏移量,是定义在View空间坐标系的 224 */ 225 int calendar_get_hitted_day_cell_index(const SCalendar* calendar, CGPoint localPt) 226 { 227 //优化1: 如果一个点不在日期区块中,那么肯定没点中,立即返回 228 CGRect daySec; 229 calendar_get_day_section_rect(calendar, &daySec); 230 231 if(!CGRectContainsPoint(daySec,localPt)) 232 return -1; 233 234 localPt.y -= daySec.origin.y; 235 236 //触摸点肯定会会点中日期区块中的某个cell 237 238 //优化2: 避免使用循环6*7次遍历整个cell,检测是否一点在该cell中,通过下面算法,可以立刻获得当前点所在的cell行列索引号 239 240 float cellWidth = daySec.size.width / 7.0F; 241 float cellHeight = daySec.size.height / 6.0F; 242 int columIdx = localPt.x / cellWidth; 243 int rowIdx = localPt.y / cellHeight; 244 245 //检测当前被点中的cell是否允许被选中,具体原理请参考 246 //函数void calendar_set_year_month(SCalendar* calendar,int year,int month)的注释 247 248 int idx = rowIdx * 7 + columIdx; 249 if(idx < calendar->dayBeginIdx || idx > calendar->dayBeginIdx + calendar->dayCount - 1) 250 return -1; 251 252 //到此说明肯定有点中的cell,返回该cell的索引号 253 return idx; 254 }
第一部分完毕,下一篇我们关注ios的实现。
用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)
标签:
原文地址:http://www.cnblogs.com/jackybu/p/5442835.html