本文爲原創,若有轉載,請註明出處:http://www.cnblogs.com/jackybujava
前言python
章節:linux
一、需求描述以及c/c++實現日期和月曆的基本操做android
二、ios實現自繪日期選擇控件ios
三、android實現自繪日期選擇控件c++
目的:算法
經過一個相對複雜的自定義自繪控件來分享:數據庫
一、ios以及android自定義自繪控件的開發流程編程
二、objc與c/c++混合編程c#
三、android ndk的環境配置,android studio ndk的編譯模式,swig在android ndk開發中的做用
1、需求描述以及c/c++實現日期和月曆的基本操做
一、需求描述:
圖1 某個月的日曆外觀 圖2 日期區間選中狀態
1) 該日期選擇控件主要用於日期過濾查詢,通常用於近n年的數據查詢。
2) 假設你點擊某個按鈕彈出該日期選擇控件時,自動定位到當前月,例如本月是4月,則4月份顯示在屏幕最下方。
3) 當你手指向上滑動時,向前n個月滾動(月份例如:4-3-2-1),手指向下滑動時,向後n個月滾動(月份例如:1-2-3-4)。
4) 日期區分爲可選擇區或不可選擇區(圖1),當你第一次點擊可選的日期,該日期會被選中(藍色)。
5) 當你第二次點擊可選的日期,則會造成一個選區(圖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的開發方式。
三、爲何選擇自定義自繪控件方式:
不論是android仍是ios,自定義控件的實現基本上有三種方式:
1) 利用androidStudio或xcode interfaceBuilder中的容器控件以及其餘控件組合拼裝而成,自定義控件不須要繼承自View或子類。你能夠進行一些事件的編寫就能夠完成不少需求。
2) 繼承自View或子類,再用現有的控件組合拼裝而成。
3) 繼承自View或子類,全部該自定義View的顯示效果由咱們來繪製出來。
這裏咱們採起第三種方式。相對來講,這種方式內存消耗要小不少,而且速度上也有必定優點吧。要知道每月都是須要42個cell表示日期,而且加上年月和星期這些區塊,都用View組合而成,內存也不算小。不論是ios仍是android,每一個View的成員變量都很多。而使用自繪控件,只要一個View就解決了。至少內存使用上能夠減小40多個View的使用,對吧?
四、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 一、初版 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 二、第二版 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 三、網上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的實現。