先上一張效果圖(原諒我還是這么無聊~~,我覺得動態(tài)的可能更能展示作品的特性)
寫這個(gè)時(shí)間選擇器之前我還沒寫過相關(guān)的東西,沒寫過其實(shí)是瞎話瞧省,以前在項(xiàng)目中用過
UIDatePicker
,所以可自定義性不是很強(qiáng),也沒啥可說的,雖然在我們的項(xiàng)目中時(shí)間選擇器很常見该默,但是認(rèn)真研究的人就不知道了……,這次我也算是認(rèn)真的看了一下UIPickerView
內(nèi)部的組成策彤。先說說內(nèi)部的組成吧栓袖。
1 UIPickerView
內(nèi)部組成
在xcode的可視化工具中你可以看到UIPikerView的結(jié)構(gòu)如下:
當(dāng)然如果匣摘,你也可以打印一下
UIPikerView
的子空間,會發(fā)現(xiàn)裹刮,它有三個(gè)子空間音榜,其中兩個(gè)是一樣的,而且高度是0.67,所以我們可以猜測這個(gè)高度是0.67的view就是那兩條灰色的分割線捧弃。不信你可以試試,簡要做以下測試
self.picker.subviews[1].hidden = YES;
self.picker.subviews[2].hidden = YES;
此時(shí)赠叼,你會驚奇的發(fā)現(xiàn)兩條灰色的分割線不見了,那么證實(shí)了我們猜測的是正確的违霞,那么接下來往下走吧嘴办。再來看結(jié)構(gòu),如果說你嫌看結(jié)構(gòu)圖麻煩的話买鸽,你可以利用打印子控件的方式看查看其內(nèi)部的控件涧郊,我是采用后者的,不過這里為了更加形象癞谒,我采用圖形結(jié)合的方式來講底燎。如下圖:
請?jiān)徫业膽卸枞姓ィ@里我把結(jié)構(gòu)圖全部展開來講吧弹砚,不再一張一張的貼圖了,
- UIPickerView的suviews 展開這個(gè)后我們看到里面又有3個(gè)
UIPickerColumnView
枢希,當(dāng)然你可以利用日志打印一下桌吃,會發(fā)現(xiàn)前三個(gè)是完全一樣的,我們可以猜測每一個(gè)代表著一列苞轿,不信你可以改變數(shù)據(jù)源試試茅诱,會發(fā)現(xiàn)猜測的正確性。 - 接下來我們進(jìn)入到每一列
UIPickerColumnView
搬卒,發(fā)現(xiàn)有三個(gè)UIView(子控件)瑟俭,前兩個(gè)完全一樣,第三個(gè)不同契邀,我猜測摆寄,第三個(gè)是中間行,也就是選擇到日期的那一行 - 以此類推坯门,你可以看到中間行里面有一個(gè)子控件微饥,名字是
UIPickerTableView
,這是蘋果內(nèi)部私有類,在UIKit框架中我們找不到它的頭文件古戴,但是依舊不影響我們獲取到它欠橘。
快上代碼,不多啰嗦了
2 為時(shí)間選擇器自定義分割線
我們可以拿到UIPickerTableView
然后利用runtime
機(jī)制取出其內(nèi)部的屬性现恼,如果你有印象的話肃续,我說過每個(gè)UIPickerColumnView
中有三個(gè)UIView
控件,每個(gè)UIView
控件中只有一個(gè)子控件UIPickerTableView
黍檩,而三個(gè)UIView
控件中的第3個(gè)才是我們選擇時(shí)間的那一行。
上述話的意思簡單翻譯為
UIPickerColumnView
中UIView
控件數(shù) =UIPickerTableView
數(shù)
我們可以拿到每一列component( 即每一UIPickerColumnView
列)中UIPickerTableView
的數(shù)目
int pickerTableViewNum = (int)self.picker.subviews[0].subviews[component].subviews.count;
遍歷吧始锚,記住第3個(gè)是選擇日期的那一行
for (int index = 0; index<pickerTableViewNum; index++) {
//取出對應(yīng)的UIPickerTableView
UIView *tableView = self.picker.subviews[0].subviews[component].subviews[index].subviews[0];
//取出UIPickerTableView內(nèi)部的成員變量列表
unsigned int count = 0;
Ivar *array = class_copyIvarList([tableView class], &count);
//遍歷所有屬性
for (int i = 0; i<count; i++) {
Ivar property = array[i];
const char *string = ivar_getName(property);
NSString *name = [[NSString alloc]initWithUTF8String:string];
//找出名字為@"_referencingCells"的屬性,取出它的值
if (![name isEqualToString:@"_referencingCells"]) continue;
NSMutableArray * cells = object_getIvar(tableView, property);
int count = (int)cells.count;
if(!count) continue;
//設(shè)置字體顏色
UIColor *textColor = nil;
//設(shè)置label背景色
UIColor *labelBackgroundColor = nil;
//遍歷UIPickerTableView 中的cell建炫,并取出每個(gè)cell中的textLabel進(jìn)行設(shè)置相關(guān)屬性
for (int i = 0; i< count; i++) {
//設(shè)置其他部分的文字顏色、大小以及l(fā)abel背景等
if (index !=pickerTableViewNum -1) {
font = self.otherTextFont? self.otherTextFont:[UIFont systemFontOfSize:16];
textColor = self.otherTextColor ? self.otherTextColor : [UIColor grayColor];
labelBackgroundColor = self.otherLabelColor ?self.otherLabelColor : [UIColor clearColor];
}else{
font = self.selectedTextFont ? self.selectedTextFont : [UIFont systemFontOfSize:16];
textColor = self.selectedTextColor ? self.selectedTextColor : [UIColor blackColor];
labelBackgroundColor = self.selectedLabelColor ? self.selectedLabelColor : [UIColor clearColor];
}
UILabel *textLabel = [cells[i] subviews][1];
textLabel.textColor = textColor;
textLabel.font = font;
textLabel.backgroundColor = labelBackgroundColor;
if (index != pickerTableViewNum - 1)
continue;
if (textLabel.subviews.count>=1)
continue;
//dynamic seperator(設(shè)置動態(tài)分割線)
if (self.pickerViewType == PickerViewTypeDynamicSperator) {
UIView *line = [[UIView alloc]initWithFrame:CGRectMake((textLabel.frame.size.width - textWidth)/2, textLabel.frame.size.height - 1, textWidth, 1)];
line.backgroundColor = self.seperateLineColor;
[textLabel addSubview:line];
}
}
}
}
//static operate line(設(shè)置靜態(tài)分割線)
if (self.pickerViewType != PickerViewTypeStaticSperator) return;
//通過多次測試疼蛾,可以粗略計(jì)算出每列之間的間隔大概是4.75
CGFloat spacing = 4.75f;
NSInteger numberOfComponent = [self numberOfComponents];
CGFloat margin = (self.width - self.componentWidth * numberOfComponent - (numberOfComponent - 1)*spacing)/2;
CGFloat textLabelOffSet = 9.0f;
CGFloat textOffSet = (self.componentWidth - textLabelOffSet - textWidth)/2;
//取出`UIPickerColumnView`中的最后一個(gè) `UIView`控件
UIView *view = [self.picker.subviews[0].subviews[component].subviews lastObject];
//UIView控件里面在修改前只有一個(gè)UIPickerTableView控件肛跌,我們需要添加靜態(tài)分割線
if (view.subviews.count>=3) {//不能多加啊
}else{
CGFloat x = (spacing+self.componentWidth)*component + margin + textLabelOffSet+textOffSet;
UIView *lineView1 = [[UIView alloc]initWithFrame:CGRectMake(x, view.height - 1, textWidth, 1)];
UIView *lineView2 = [[UIView alloc]initWithFrame:CGRectMake(x, 0, textWidth, 1)];
lineView1.backgroundColor = [UIColor blueColor];
lineView2.backgroundColor = [UIColor blueColor];
[view addSubview:lineView1];
[view addSubview:lineView2];
}
上述代碼基本是設(shè)置所有分割線部分的關(guān)鍵代碼
3 關(guān)于日期的處理
這部分就不多做闡述了,主要是對每月天數(shù)的處理稍微復(fù)雜點(diǎn)察郁,至于其他的基本好處理衍慎,我們只要知道1、3皮钠、5稳捆、7、8麦轰、10乔夯、12是31天,4款侵、6末荐、9、11是30天新锈,2月份又分為平年和閏年甲脏,閏年29天,平年28天即可妹笆,許多demo種也有相關(guān)的計(jì)算块请,我覺得我代碼中的書寫應(yīng)該也可以比較清晰的闡述,還有就是滑動的時(shí)的日期更新拳缠,我們需要注意一點(diǎn)兒小問題墩新,如果想看內(nèi)部實(shí)現(xiàn)的話歡迎大家看我的源碼https://github.com/DreamOfXM/XMDatePicker.git
相關(guān)使用我已經(jīng)在github上
如果發(fā)現(xiàn)有什么問題,一定要給我提出來哦窟坐,當(dāng)然也歡迎交流相關(guān)技術(shù)問題