iOS中封裝一個(gè)自定義UIPickerView(Button篇)

UIPickerView是iOS開(kāi)發(fā)中,相當(dāng)常用的一個(gè)UI控件,用于滾動(dòng)選擇選項(xiàng)。也是項(xiàng)目中經(jīng)常復(fù)用的一個(gè)控件,封裝成一個(gè)統(tǒng)一風(fēng)格的庫(kù),可以減少很多代碼量。一般還會(huì)在PickerView上加上Toolbar和確定取消按鈕。
點(diǎn)擊button彈出picker,并改變指定label的值,效果如下圖所示。



最終目的是在viewcontroller中button的event reponse中調(diào)用封裝好的庫(kù)的方法進(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è)方面說(shuō)

1. 數(shù)據(jù)

  • 傳入數(shù)據(jù)(上層view對(duì)象,數(shù)組array,最后的值)
  • 改變的值(利用block傳值回調(diào))
  • UIPickerView的Delegate和DataSource方法的實(shí)現(xiàn)

上層view對(duì)象和數(shù)組array沒(méi)啥可說(shuō)的,關(guān)于取消按鈕的實(shí)現(xiàn),個(gè)人想法是把彈出picker改變前最后的值傳進(jìn)view的內(nèi)部并存儲(chǔ)起來(lái),等待按鈕的動(dòng)作響應(yīng)判斷是否取出。(但個(gè)人感覺(jué)把這個(gè)值傳進(jìn)去實(shí)現(xiàn)不太優(yōu)雅,但水平不夠沒(méi)想到其它實(shí)現(xiàn)方法,希望交流)
改變值用利用block方法傳值,不用delegate和通知的原因是感覺(jué)都太復(fù)雜了,通知還需要注冊(cè),但block的使用要注意避免循環(huán)引用導(dǎo)致內(nèi)存沒(méi)辦法得到釋放的問(wèn)題。
在.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)到當(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滾動(dòng)里每行文字的值及相關(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)先級(jí)比
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
這個(gè)方法優(yōu)先級(jí)高,也就是說(shuō)會(huì)覆蓋后面那個(gè)方法里的設(shè)置,后面的方法只能確定每行返回的方法的值,沒(méi)辦法對(duì)字體大小,顏色,分割線等進(jìn)行自定義,需要自定義就使用第一個(gè)方法。

2. 視圖

視圖上,由一個(gè)壓黑背景的view上面加上一個(gè)包含確定和取消兩個(gè)按鈕和pickerview的containview組成。
先在最開(kāi)始進(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)擊動(dòng)作等,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)擊事件

很簡(jiǎn)單,見(jiàn)代碼即可。取消的話把傳進(jìn)來(lái)的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]);//未滑動(dòng)的話默認(rèn)為第一個(gè)數(shù)據(jù)
    [pickerView initView];
    [view addSubview:pickerView];
}

最后

所有源碼和Demo
這是我第一次寫(xiě)技術(shù)類文章,雖然不是什么很深入的問(wèn)題,但希望能分享給有需要的人。

如果您覺(jué)得有幫助,不妨給個(gè)star鼓勵(lì)一下,歡迎關(guān)注&交流
有任何問(wèn)題歡迎評(píng)論私信或者提issue
QQ:757765420
Email:nemocdz@gmail.com
Github:Nemocdz
微博:@Nemocdz

謝謝觀看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • UIPickerView也是一個(gè)選擇器控件,它比UIDatePicker更加通用,它可以生成單列的選擇器,也可生成...
    小蘑菇2閱讀 3,724評(píng)論 3 5
  • 廢話不多說(shuō),直接上干貨 ---------------------------------------------...
    小小趙紙農(nóng)閱讀 3,646評(píng)論 0 15
  • UIPickerView 繼承了UIView 沒(méi)有繼承UIControl UIPickerView的時(shí)間處理由其委...
    nalis風(fēng)閱讀 1,675評(píng)論 0 0
  • *7月8日上午 N:Block :跟一個(gè)函數(shù)塊差不多,會(huì)對(duì)里面所有的內(nèi)容的引用計(jì)數(shù)+1,想要解決就用__block...
    炙冰閱讀 2,726評(píng)論 1 14
  • { 11、核心動(dòng)畫(huà) 需要簽協(xié)議,但是系統(tǒng)幫簽好 一、CABasicAnimation 1、創(chuàng)建基礎(chǔ)動(dòng)畫(huà)對(duì)象 CAB...
    CYC666閱讀 1,697評(píng)論 2 4

友情鏈接更多精彩內(nèi)容