UIPickerView是iOS開發(fā)中懦铺,相當(dāng)常用的一個(gè)UI控件担败,用于滾動選擇選項(xiàng)殿托。也是項(xiàng)目中經(jīng)常復(fù)用的一個(gè)控件霹菊,封裝成一個(gè)統(tǒng)一風(fēng)格的庫,可以減少很多代碼量支竹。一般還會在PickerView上加上Toolbar和確定取消按鈕旋廷。
點(diǎn)擊button彈出picker,并改變指定label的值礼搁,效果如下圖所示饶碘。
最終目的是在viewcontroller中button的event reponse中調(diào)用封裝好的庫的方法進(jìn)行傳值及操作。
- (IBAction)showPicker:(UIButton *)sender {
NSArray *array = @[@"電子科技大學(xué)",@"清華大學(xué)",@"四川大學(xué)",@"華中科技大學(xué)",@"西安電子科技大學(xué)"];
[CDZPicker showPickerInView:self.view withObjectsArray:array withlastString:self.label.text withStringBlock:^(NSString *string) {
self.label.text = string;
}];
}
實(shí)現(xiàn)思路從數(shù)據(jù)馒吴,視圖扎运,按鈕處理三個(gè)方面說
1. 數(shù)據(jù)
- 傳入數(shù)據(jù)(上層view對象卑雁,數(shù)組array,最后的值)
- 改變的值(利用block傳值回調(diào))
- UIPickerView的Delegate和DataSource方法的實(shí)現(xiàn)
上層view對象和數(shù)組array沒啥可說的绪囱,關(guān)于取消按鈕的實(shí)現(xiàn)测蹲,個(gè)人想法是把彈出picker改變前最后的值傳進(jìn)view的內(nèi)部并存儲起來,等待按鈕的動作響應(yīng)判斷是否取出鬼吵。(但個(gè)人感覺把這個(gè)值傳進(jìn)去實(shí)現(xiàn)不太優(yōu)雅扣甲,但水平不夠沒想到其它實(shí)現(xiàn)方法,希望交流)
改變值用利用block方法傳值齿椅,不用delegate和通知的原因是感覺都太復(fù)雜了琉挖,通知還需要注冊,但block的使用要注意避免循環(huán)引用導(dǎo)致內(nèi)存沒辦法得到釋放的問題涣脚。
在.h文件中定義block的別名便于使用
typedef void (^CDZStringResultBlock)(NSString *string);
.m中增加以下屬性
@property (nonatomic,strong) NSArray *dataArray;
@property (nonatomic,strong) NSString *lastString;
@property (nonatomic, copy) CDZStringResultBlock block;
實(shí)現(xiàn)Pickerview的Delegate和DataSource協(xié)議
<UIPickerViewDelegate,UIPickerViewDataSource>
實(shí)現(xiàn)Pickerview的Delegate和DataSource相關(guān)方法
#pragma mark - PickerDataSource
//返回picker列數(shù)
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
//picker行數(shù)
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return self.dataArray.count;
}
#pragma mark - PickerDelegate
//返回每行高度
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
return 44;
}
//滑動到當(dāng)行進(jìn)行的操作示辈,這里把當(dāng)行的數(shù)據(jù)回調(diào)
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
self.block(self.dataArray[row]);
}
//要修改picker滾動里每行文字的值及相關(guān)屬性,分割線等在此方法里設(shè)置
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
//設(shè)置分割線的顏色,這里設(shè)為隱藏
for(UIView *singleLine in pickerView.subviews){
if (singleLine.frame.size.height < 1) {
singleLine.backgroundColor = [UIColor clearColor];
}
}
//設(shè)置文字的屬性
UILabel *genderLabel = [UILabel new];
genderLabel.textAlignment = NSTextAlignmentCenter;
genderLabel.text = self.dataArray[row];
genderLabel.font = [UIFont systemFontOfSize:23.0];
genderLabel.textColor = [UIColor blackColor];
return genderLabel;
}
另外有一點(diǎn)要注意
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
這個(gè)方法的優(yōu)先級比
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
這個(gè)方法優(yōu)先級高遣蚀,也就是說會覆蓋后面那個(gè)方法里的設(shè)置矾麻,后面的方法只能確定每行返回的方法的值,沒辦法對字體大小芭梯,顏色险耀,分割線等進(jìn)行自定義,需要自定義就使用第一個(gè)方法玖喘。
2. 視圖
視圖上甩牺,由一個(gè)壓黑背景的view上面加上一個(gè)包含確定和取消兩個(gè)按鈕和pickerview的containview組成。
先在最開始進(jìn)行一些顏色累奈,屏幕大小的宏定義和全局靜態(tài)變量定義贬派,方便使用
#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
#define BACKGROUND_BLACK_COLOR [UIColor colorWithRed:0.412 green:0.412 blue:0.412 alpha:0.7]
static const int pickerViewHeight = 228;
static const int toolBarHeight = 44;
進(jìn)行view的布局,增加button點(diǎn)擊動作等澎媒,pickerview要指定datasource和delegate為self
- (void)initView{
UIView *containerView = [[UIView alloc]initWithFrame:CGRectMake(0, SCREEN_HEIGHT - pickerViewHeight, SCREEN_WIDTH, pickerViewHeight)];
containerView.backgroundColor = [UIColor whiteColor];
UIButton *btnOK = [[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH -70, 5, 40, 30)];
btnOK.titleLabel.font = [UIFont systemFontOfSize:18.0];
[btnOK setTitle:@"確定" forState:UIControlStateNormal];
[btnOK setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[btnOK addTarget:self action:@selector(pickerViewBtnOk:) forControlEvents:UIControlEventTouchUpInside];
[containerView addSubview:btnOK];
UIButton *btnCancel = [[UIButton alloc] initWithFrame:CGRectMake(30, 5, 40, 30)];
btnCancel.titleLabel.font = [UIFont systemFontOfSize:18.0];
[btnCancel setTitle:@"取消" forState:UIControlStateNormal];
[btnCancel setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[btnCancel addTarget:self action:@selector(pickerViewBtnCancel:) forControlEvents:UIControlEventTouchUpInside];
[containerView addSubview:btnCancel];
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 32, SCREEN_WIDTH, pickerViewHeight - toolBarHeight)];
pickerView.backgroundColor = [UIColor whiteColor];
pickerView.delegate = self;
pickerView.dataSource = self;
[containerView addSubview:pickerView];
self.backgroundColor = BACKGROUND_BLACK_COLOR;
[self addSubview:containerView];
}
3.響應(yīng)按鈕點(diǎn)擊事件
很簡單搞乏,見代碼即可。取消的話把傳進(jìn)來的lastString傳回去即可旱幼。
#pragma mark - event response
- (void)pickerViewBtnOk:(UIButton *)btn{
[self removeFromSuperview];
}
- (void)pickerViewBtnCancel:(UIButton *)btn{
self.block (self.lastString);
[self removeFromSuperview];
}
封裝成工廠方法
+ (void)showPickerInView:(UIView *)view
withObjectsArray:(NSArray *)array
withlastString:(NSString *)string
withStringBlock:(CDZStringResultBlock)stringBlock{
CDZPicker *pickerView = [[CDZPicker alloc]initWithFrame:view.bounds];
pickerView.dataArray = array;
pickerView.lastString = string;
pickerView.block = stringBlock;
pickerView.block(array[0]);//未滑動的話默認(rèn)為第一個(gè)數(shù)據(jù)
[pickerView initView];
[view addSubview:pickerView];
}
最后
所有源碼和Demo
這是我第一次寫技術(shù)類文章查描,雖然不是什么很深入的問題突委,但希望能分享給有需要的人柏卤。
如果您覺得有幫助,不妨給個(gè)star鼓勵(lì)一下,歡迎關(guān)注&交流
有任何問題歡迎評論私信或者提issue
QQ:757765420
Email:nemocdz@gmail.com
Github:Nemocdz
微博:@Nemocdz