iOS自定義日期、時間、城市選擇器

選擇器,我想大家都不陌生,當(dāng)需要用戶去選擇某些范圍值內(nèi)的一個固定值時,我們會采用選擇器的方式。選擇器可以直觀的提示用戶選擇的值范圍、統(tǒng)一信息的填寫格式,同時也方便用戶快速的進(jìn)行選擇,比如對于性別,正常情況下就只有男女兩種情況,那這時候用一個選擇器給用戶進(jìn)行選擇的話,可以避免錯誤數(shù)據(jù)的輸入,也更方便用戶去填寫。再比如需要獲取用戶的生日信息時,采用選擇器的方式可以統(tǒng)一生日的格式,如果讓用戶自行輸入的話,可能會出現(xiàn)各種各樣的生日信息格式,不利于數(shù)據(jù)的存儲,但是采用選擇器的方式的話,用戶可找到對應(yīng)的日期進(jìn)行選擇即可。

在iOS有專門的一個選擇器類UIPickerView,進(jìn)入UIPickerView的頭文件,我們可以發(fā)現(xiàn) UIPickerView直接繼承了UIView,其事件處理通過代理方法完成,所以創(chuàng)建UIPickerView的時候記得簽它的代理UIPickerViewDataSourceUIPickerViewDelegate。其實(shí)它和UITbleView有點(diǎn)像,不過UIPickerView還多了個列屬性,UITbleView我們都很熟了,所以可以對比UITbleView的相關(guān)屬性和代理方法來學(xué)習(xí)記憶UIPickerView。

一. UIPickerView的代理方法

(1)UIPickerViewDataSource對應(yīng)的代理方法有(其代理方法必須要實(shí)現(xiàn)):

返回顯示的列數(shù)

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;

返回每一列中需要顯示的行數(shù)

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;

(2)UIPickerViewDelegate對應(yīng)的代理方法(其代理方法根據(jù)需求進(jìn)行選擇性實(shí)現(xiàn)):

*返回每一列的寬度 *

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component;

返回每一列的高度

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component ;

*返回UIPickerView控件中指定列的列表項(xiàng)的要顯示的內(nèi)容 *

- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component ;

返回UIView,作為該UIPickerView控件中指定列的指定行的顯示視圖

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view ;

選擇指定列中的指定行

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component ;

二、UIPickerView和UIDatePicker。

UIDatePicker是系統(tǒng)幫我們封裝好的一個時間日期選擇器,繼承于UIControl,UIDatePicker有一定的局限性,因?yàn)樗挥兴姆N顯示樣式:

UIDatePickerModeTime,          
UIDatePickerModeDate,          
UIDatePickerModeDateAndTime, 
UIDatePickerModeCountDownTimer, 

如果需求和這四種樣式都不符合的話,那么就沒辦法使用UIDatePicker,比如當(dāng)只需要顯示年、月信息的時候,顯然UIDatePicker沒辦法滿足我們的需求,那這時我們只能通過UIPickerView來自定義自己想要的選擇器。

三、UIPickerView的自定義使用

(1)創(chuàng)建基類繼承于UIView的WXZBasePickView。

我們常見的選擇器的樣式是一個帶透明背景色的view,底部是內(nèi)容的選擇器,有確定和取消按鈕,大致如圖:

選擇器

所以我們創(chuàng)建一個基類view,這個view的樣式如圖所示樣式,之后根據(jù)內(nèi)容的差別創(chuàng)建基于該view的選擇器。

在.h中聲明各個屬性及方法

#import <UIKit/UIKit.h>

@interface WXZBasePickView : UIView

@property (nonatomic, strong) UIView *contentView;

//選擇器
@property (nonatomic, strong)UIPickerView *pickerView;
//取消按鈕
@property (nonatomic, strong)UIButton *cancelButton;
 //確定按鈕
@property (nonatomic, strong)UIButton *confirmButton;

//選擇器每一列的高度
@property (nonatomic, assign)CGFloat pickerViewHeight;

/**
 *  創(chuàng)建視圖,初始化視圖時初始數(shù)據(jù)
 */
- (void)initPickView;

/**
 *  確認(rèn)按鈕的點(diǎn)擊事件
 */
- (void)clickConfirmButton;

/**
 *  pickerView的顯示
 */
- (void)show;

/**
 *  移除pickerView
 */
- (void)disMiss;


@end

在.m中實(shí)現(xiàn)相關(guān)方法

#import "WXZBasePickView.h"
#define ScreenWidth [UIScreen mainScreen].bounds.size.width
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
@implementation WXZBasePickView

- (instancetype)init
{
    self = [super init];
    if (self) {
    
        _pickerViewHeight      = 250;
        self.bounds = [UIScreen mainScreen].bounds;
        self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.64];
        self.layer.opacity = 0.0;
        
        UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(disMiss)];
        self.userInteractionEnabled = YES;
        [self addGestureRecognizer:tap];
     
        [self addSubview:self.contentView];
        [self.contentView addSubview:self.pickerView];
        [self.contentView addSubview:self.cancelButton];
        [self.contentView addSubview:self.confirmButton];
        
        [self initPickView];
     }
    return self;
}
//初始化選擇器內(nèi)容,創(chuàng)建子類時需實(shí)現(xiàn)該父類方法
-(void)initPickView{
    
}
//點(diǎn)擊確定按鈕
- (void)clickConfirmButton
{
    [self disMiss];
}

//點(diǎn)擊取消按鈕
- (void) clickCancelButton
{
    [self disMiss];
}

//顯示選擇器
 - (void)show
{
    [[UIApplication sharedApplication].keyWindow addSubview:self];
    [self setCenter:[UIApplication sharedApplication].keyWindow.center];
    [[UIApplication sharedApplication].keyWindow bringSubviewToFront:self];
    
    
        CGRect frame =  self.contentView.frame;
       frame.origin.y -= self.contentView.frame.size.height;
        [UIView animateWithDuration:0.4 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            [self.layer setOpacity:1.0];
            self.contentView.frame = frame;
            
        } completion:^(BOOL finished) {
        }];
    
    }

//移除選擇器
- (void)disMiss
{
 
        CGRect frame =  self.contentView.frame;
        frame.origin.y += self.contentView.frame.size.height;
        [UIView animateWithDuration:0.4 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            [self.layer setOpacity:0.0];
            self.contentView.frame = frame;
        } completion:^(BOOL finished) {
            [self removeFromSuperview];
        }];
    
}
//設(shè)置選擇器的高度
- (void)setPickerViewHeight:(CGFloat)pickerViewHeight
{
    _pickerViewHeight = pickerViewHeight;
    self.contentView.frame = CGRectMake(self.contentView.frame.origin.x, self.contentView.frame.origin.y, self.contentView.frame.size.width, pickerViewHeight);
}

- (UIView *)contentView
{
    if (!_contentView) {
 
        _contentView = [[UIView alloc]initWithFrame:CGRectMake(0, ScreenHeight, ScreenWidth, self.pickerViewHeight)];
        [_contentView setBackgroundColor:[UIColor whiteColor]];
    }
    return _contentView;
}


- (UIPickerView *)pickerView
{
    if (!_pickerView) {
  
        _pickerView = [[UIPickerView alloc]initWithFrame:CGRectMake(0,  0, self.contentView.frame.size.width, self.contentView.frame.size.height)];
        [_pickerView setBackgroundColor:[UIColor whiteColor]];
         
    }
    return _pickerView;
}

- (UIButton *)cancelButton
{
    if (!_cancelButton) {
      
        _cancelButton = [[UIButton alloc]initWithFrame:CGRectMake(16, 0, 44, 44)];
        [_cancelButton setTitle:@"取消" forState:UIControlStateNormal];
        [_cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
  
        [_cancelButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
        [_cancelButton addTarget:self action:@selector(clickCancelButton) forControlEvents:UIControlEventTouchUpInside];
    }
    return _cancelButton;
}

- (UIButton *)confirmButton
{
    if (!_confirmButton) {
    
        _confirmButton = [[UIButton alloc]initWithFrame:CGRectMake(self.contentView.frame.size.width - self.cancelButton.frame.size.width - self.cancelButton.frame.origin.x, self.cancelButton.frame.origin.y, self.cancelButton.frame.size.width, self.cancelButton.frame.size.height)];
        [_confirmButton setTitle:@"確定" forState:UIControlStateNormal];
        [_confirmButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
      
        [_confirmButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
        [_confirmButton addTarget:self action:@selector(clickConfirmButton) forControlEvents:UIControlEventTouchUpInside];
    }
    return _confirmButton;
}
 

@end
(2)、自定義一個日期選擇器,可選擇顯示年、月或者年、月、日以及是否顯示“至今”選項(xiàng)。

創(chuàng)建繼承于我們自定義好的WXZBasePickView的日期選擇器WXZPickDateView
.h聲明相關(guān)屬性和方法

#import "WXZBasePickView.h"
@class WXZBasePickView;
//選擇器的選擇代理方法
@protocol  PickerDateViewDelegate<NSObject>
- (void)pickerDateView:(WXZBasePickView *)pickerDateView selectYear:(NSInteger)year selectMonth:(NSInteger)month selectDay:(NSInteger)day;
@end

@interface WXZPickDateView : WXZBasePickView
 
@property(nonatomic, weak)id <PickerDateViewDelegate>delegate ;
@property(nonatomic, assign)BOOL isAddYetSelect;//是否增加至今的選項(xiàng)
@property(nonatomic, assign)BOOL isShowDay;//是否顯示日
//設(shè)置默認(rèn)顯示的值
-(void)setDefaultTSelectYear:(NSInteger)defaultSelectYear defaultSelectMonth:(NSInteger)defaultSelectMonth defaultSelectDay:(NSInteger)defaultSelectDay;

@end
```
.m實(shí)現(xiàn)相關(guān)方法
 
```
#import "WXZPickDateView.h"
@interface WXZPickDateView()<UIPickerViewDataSource, UIPickerViewDelegate>
/** 選擇的年 */
@property (nonatomic, assign)NSInteger selectYear;
/** 選擇的月 */
@property (nonatomic, assign)NSInteger selectMonth;
/** 選擇的日 */
@property (nonatomic, assign)NSInteger selectDay;
@property (nonatomic, assign)NSInteger currentYear;
@property (nonatomic, assign)NSInteger currentMonth;
@property (nonatomic, assign)NSInteger currentDay;
@property (nonatomic, assign)NSInteger defaultYear;
@property (nonatomic, assign)NSInteger defaultMonth;
@property (nonatomic, assign)NSInteger defaultDay;

@property (nonatomic, assign)NSInteger minShowYear;
@property (nonatomic, assign)NSInteger yearSum;
@end
@implementation WXZPickDateView

- (void)initPickView
{
    [super initPickView];
    _minShowYear = 1940;//最小年份
    NSCalendar *gregorian = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    // 獲取當(dāng)前日期
    NSDate* dt = [NSDate date];
    // 指定獲取指定年、月、日、時、分、秒的信息
    unsigned unitFlags = NSCalendarUnitYear |
    NSCalendarUnitMonth |  NSCalendarUnitDay |
    NSCalendarUnitHour |  NSCalendarUnitMinute |
    NSCalendarUnitSecond | NSCalendarUnitWeekday;
    // 獲取不同時間字段的信息
    NSDateComponents* comp = [gregorian components: unitFlags fromDate:dt];
    
    _yearSum = comp.year-_minShowYear+1;
    _currentYear=comp.year;
    _currentMonth=comp.month;
    _currentDay=comp.day;
 
    
    _selectYear  = comp.year;
    _selectMonth = comp.month;
    _selectDay   = comp.day;
   
    _defaultYear = comp.year;
    _defaultMonth = comp.month;
    _defaultDay=comp.day;
    [self.pickerView setDelegate:self];
    [self.pickerView setDataSource:self];
       
}
-(void)setDefaultTSelectYear:(NSInteger)defaultSelectYear defaultSelectMonth:(NSInteger)defaultSelectMonth defaultSelectDay:(NSInteger)defaultSelectDay{
  
    if (defaultSelectYear!=0) {
     _defaultYear=defaultSelectYear;
    }
    
    if (defaultSelectMonth!=0) {
        _defaultMonth = defaultSelectMonth;
    }
    
    if (defaultSelectDay!=0) {
         _defaultDay=defaultSelectDay;
    }
    
   
    if (defaultSelectYear==-1) {
        _defaultYear=_currentYear+1;
        _defaultMonth=1;
        _defaultDay=1;
    }
    
   
    [self.pickerView selectRow:(_defaultYear - _minShowYear) inComponent:0 animated:NO];
    [self.pickerView reloadComponent:1];
    [self.pickerView selectRow:(_defaultMonth - 1) inComponent:1 animated:NO];
    if (_isShowDay==YES) {
        [self.pickerView reloadComponent:2];
        [self.pickerView selectRow:_defaultDay inComponent:1 animated:NO];
    }
    
    [self refreshPickViewData];
    
}
-(void)setIsAddYetSelect:(BOOL)isAddYetSelect{
    _isAddYetSelect = isAddYetSelect;
}


- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
//判斷是否要顯示日,如果顯示則返回3列,反之返回2列
    if (_isShowDay==YES) {
        return 3;
    }else{
        return 2;
    }
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if (component == 0) {
        if (_isAddYetSelect==YES) {
            //顯示至今選項(xiàng)的話,需要比總共要顯示的年份多返回一行
            return self.yearSum+1;
            
        }else{
          
           return self.yearSum;
        }
    }else if(component == 1) {
        NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
        if (yearSelected==_currentYear+1) {
            //至今選項(xiàng)的時候月份信息不返回
            return 0;
        }else{
            
            return 12;
        }
    }else {
        NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
        if (yearSelected==_currentYear+1) {
             //至今選項(xiàng)的時候日信息不返回
            return 0;
        }else{
        NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
        NSInteger monthSelected = [pickerView selectedRowInComponent:1] + 1;
        return  [self getDaysWithYear:yearSelected month:monthSelected];
        }
    }
    
    
}
//根據(jù)年、月判斷日期天數(shù)
- (NSInteger)getDaysWithYear:(NSInteger)year
                       month:(NSInteger)month
{
    switch (month) {
        case 1:
            return 31;
            break;
        case 2:
            if (year%400==0 || (year%100!=0 && year%4 == 0)) {
                return 29;
            }else{
                return 28;
            }
            break;
        case 3:
            return 31;
            break;
        case 4:
            return 30;
            break;
        case 5:
            return 31;
            break;
        case 6:
            return 30;
            break;
        case 7:
            return 31;
            break;
        case 8:
            return 31;
            break;
        case 9:
            return 30;
            break;
        case 10:
            return 31;
            break;
        case 11:
            return 30;
            break;
        case 12:
            return 31;
            break;
        default:
            return 0;
            break;
    }
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    //每一行的高度
    return 36;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    
    NSInteger selectYear;
    NSInteger selectMonth;
    
    switch (component) {
        case 0:
    
            [pickerView reloadComponent:1];
            if (_isAddYetSelect==YES) {
                selectYear = row+_minShowYear+1;
            }else{
                selectYear = row+_minShowYear;
            }
            if (_isShowDay==YES) {
                [pickerView reloadComponent:2];
            }
            break;
        case 1:
            selectMonth = row+1;
            if (_isShowDay==YES) {
                [pickerView reloadComponent:2];
            }
        default:
            break;
    }
 
    [self refreshPickViewData];
 
}

 
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{
    
    NSString *text;
    if (component == 0) {
     
        if (_isAddYetSelect==YES) {
            
            if (row+_minShowYear==_currentYear+1) {
                text=@"至今";
                
            }else{
                
                
                text =  [NSString stringWithFormat:@"%zd年", row + _minShowYear];
                
            }
            
        }else{
            
            text =  [NSString stringWithFormat:@"%zd年", row + _minShowYear];
        }
        
    }else if (component == 1){
        if (_isAddYetSelect==YES) {
            NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
            if (yearSelected==_currentYear+1) {
                text =  [NSString stringWithFormat:@""];
            }else{
                text =  [NSString stringWithFormat:@"%zd月", row + 1];
            }
        }else{
            text =  [NSString stringWithFormat:@"%zd月", row + 1];
        }
        
        
    }else{
        text = [NSString stringWithFormat:@"%zd日", row + 1];
    }
    
    UILabel *label = [[UILabel alloc]init];
    label.textAlignment = 1;
    label.font = [UIFont systemFontOfSize:16];
    label.text = text;
    
    return label;
}


- (void)clickConfirmButton
{
    
    
    if ([self.delegate respondsToSelector:@selector(pickerDateView:selectYear:selectMonth:selectDay:)]) {
        
        [self.delegate pickerDateView:self selectYear:self.selectYear selectMonth:self.selectMonth selectDay:self.selectDay];
    
    }
    
    [super clickConfirmButton];
    
}



- (void)refreshPickViewData
{
    
    self.selectYear  = [self.pickerView selectedRowInComponent:0] + self.minShowYear;
    
    self.selectMonth = [self.pickerView selectedRowInComponent:1] + 1;
    if (_isShowDay==YES) {
          self.selectDay   = [self.pickerView selectedRowInComponent:2] + 1;
    }
    
}
 

- (void)setYearLeast:(NSInteger)yearLeast
{
    _minShowYear = yearLeast;
}

- (void)setYearSum:(NSInteger)yearSum
{
    _yearSum = yearSum;
}

-(void)setIsShowDay:(BOOL)isShowDay{
    _isShowDay=isShowDay;
}

@end
```
######(3)   創(chuàng)建繼承于WXZBasePickView的時間選擇器WXZPickTimeView。
.h聲明屬性及相關(guān)方法
```
#import "WXZBasePickView.h"
@class WXZPickTimeView;

@protocol  PickTimeViewDelegate<NSObject>
- (void)pickerTimeView:(WXZPickTimeView *)pickerTimeView selectHour:(NSInteger)hour selectMinute:(NSInteger)minute ;

@end
@interface WXZPickTimeView : WXZBasePickView
@property(nonatomic, weak)id <PickTimeViewDelegate>delegate ;

-(void)setDefaultHour:(NSInteger)hour defaultMinute:(NSInteger)minute  ;
@end
```
.m實(shí)現(xiàn)相關(guān)方法
```
#import "WXZPickTimeView.h"
@interface WXZPickTimeView () <UIPickerViewDataSource, UIPickerViewDelegate>{
    UIDatePicker    *_datePicker;
}

@property (nonatomic, assign)NSInteger selectHour;
@property (nonatomic, assign)NSInteger selectMinute;
@property (nonatomic, assign)NSInteger day;
@property (nonatomic, assign)NSInteger defaultHour;
@property (nonatomic, assign)NSInteger defaultMinute;

@end

@implementation WXZPickTimeView

 - (void)initPickView
{
    [super initPickView];
    
   
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    // 獲取當(dāng)前日期
    NSDate* dt = [NSDate date];
    // 定義一個時間字段的旗標(biāo),指定將會獲取指定年、月、日、時、分、秒的信息
    unsigned unitFlags = NSCalendarUnitYear |
    NSCalendarUnitMonth |  NSCalendarUnitDay |
    NSCalendarUnitHour |  NSCalendarUnitMinute |
    NSCalendarUnitSecond | NSCalendarUnitWeekday;
    // 獲取不同時間字段的信息
    NSDateComponents* comp = [gregorian components: unitFlags
                                          fromDate:dt];
    
    _selectHour=comp.hour;
    _selectMinute=comp.minute;
   
    [self.pickerView setDelegate:self];
    [self.pickerView setDataSource:self];
    
    [self.pickerView selectRow:_selectHour inComponent:0 animated:NO];
    [self.pickerView selectRow:_selectMinute inComponent:1 animated:NO];
    
    
}
-(void)setDefaultHour:(NSInteger)hour defaultMinute:(NSInteger)minute{
 
    if (hour!=0) {
        
     _defaultHour=hour;
 
        
    }else{
        _defaultHour=_selectHour;
  
    }
    if (minute!=0) {
        
 
        _defaultMinute = minute;
 
    }else{
       
        _defaultMinute=_selectMinute;
    }
    [self.pickerView selectRow:_defaultHour inComponent:0 animated:NO];
    [self.pickerView reloadComponent:1];
    [self.pickerView selectRow:_defaultMinute inComponent:1 animated:NO];
    [self refreshPickTimeViewData];
    
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if (component == 0) {
        return 24;
    }else {
        return 60;
    }
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    return 36;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    switch (component) {
        case 0:
            [pickerView reloadComponent:1];
            
            break;
        case 1:
            
        default:
            break;
    }
    
    [self refreshPickTimeViewData];
}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{
    
    NSString *text;
    if (component == 0) {
        if (row<10) {
            text =  [NSString stringWithFormat:@"0%zd時", row];
        }else{
            text =  [NSString stringWithFormat:@"%zd時", row];
        }
    }else if (component == 1){
        if (row<10) {
            text =  [NSString stringWithFormat:@"0%zd分", row ];
        }else{
            text =  [NSString stringWithFormat:@"%zd分", row ];
        }
    }else{
        
    }
    
    UILabel *label = [[UILabel alloc]init];
    label.textAlignment = 1;
    label.font = [UIFont systemFontOfSize:16];
    label.text = text;
    return label;
}

- (void)clickConfirmButton
{
    if ([self.delegate respondsToSelector:@selector(pickerTimeView:selectHour:selectMinute:)]) {
        
        [self.delegate pickerTimeView:self selectHour:self.selectHour selectMinute:self.selectMinute];
        
    }
    
    [super clickConfirmButton];
}

- (void)refreshPickTimeViewData
{
    self.selectHour  = [self.pickerView selectedRowInComponent:0];
    self.selectMinute = [self.pickerView selectedRowInComponent:1];
    
}
@end
```
######(4)創(chuàng)建繼承于WXZBasePickView的城市選擇器WXZPickCityView。
.h聲明相關(guān)屬性和方法
```
#import "WXZBasePickView.h"
@class WXZPickCityView;

@protocol  PickerCityViewDelegate<NSObject>

- (void)pickerArea:(WXZPickCityView *)pickerArea selectProvince:(NSString *)province selectCity:(NSString *)city;

@end
@interface WXZPickCityView : WXZBasePickView
@property(nonatomic, weak)id <PickerCityViewDelegate>delegate ;

/**設(shè)置默認(rèn)的省市*/

-(void)setDefaultCity:(NSString *)defaultCity  DefaultProvience:(NSString *)defaultProvience;
@end

```
.m實(shí)現(xiàn)相關(guān)方法
```
#import "WXZPickCityView.h"
@interface WXZPickCityView()<UIPickerViewDataSource, UIPickerViewDelegate>


@property (nonatomic, strong, nullable)NSArray *areaDataSource;

@property (nonatomic, strong, nullable)NSMutableArray *provinceArray;

@property (nonatomic, strong, nullable)NSMutableArray *cityArray;

@property (nonatomic, strong, nullable)NSMutableArray *selectedArray;//當(dāng)前選中的數(shù)組

@property (nonatomic, strong, nullable)NSString *selectProvince;

@property (nonatomic, strong, nullable)NSString *selectCity;

@end

@implementation WXZPickCityView


- (void)initPickView
{
    [super initPickView];
    for (NSDictionary *dic in self.areaDataSource) {
        [self.provinceArray addObject:dic[@"state"]];
    }
    
    NSMutableArray *citysArr = [NSMutableArray arrayWithArray:[self.areaDataSource firstObject][@"cities"]];
    
    
    for (NSDictionary *dic in citysArr) {
        [self.cityArray addObject:dic[@"city"]];
    }
    
    self.selectProvince = self.provinceArray[0];
    self.selectCity = self.cityArray[0];
    
    
    [self.pickerView setDelegate:self];
    [self.pickerView setDataSource:self];
    
}

//設(shè)置默認(rèn)顯示的省市
-(void)setDefaultCity:(NSString *)defaultCity DefaultProvience:(NSString *)defaultProvience{
    
    for (NSInteger i = 0; i<_provinceArray.count; i++) {
        
        if ([_provinceArray[i] isEqualToString:defaultProvience]) {
            
            [self.pickerView selectRow:i inComponent:0 animated:NO];
            self.selectedArray = self.areaDataSource[i][@"cities"];
            
            [self.cityArray removeAllObjects];
            [self.selectedArray enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) {
                [self.cityArray addObject:obj[@"city"]];
            }];
            for (NSInteger j= 0; j<_cityArray.count; j++) {
                
                if ([defaultCity isEqualToString:_cityArray[j]]) {
                    
                    [self.pickerView selectRow:i inComponent:0 animated:NO];
                    [self.pickerView reloadComponent:1];
                    [self.pickerView selectRow:j inComponent:1 animated:NO];
                    [self refreshSelectAreaData];
                }
            }
        }
        
        
    }
    
}


- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if (component == 0) {
        return self.provinceArray.count;
    }else  {
        return self.cityArray.count;
    }
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    return 36;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    if (component == 0) {
        self.selectedArray = self.areaDataSource[row][@"cities"];
        
        [self.cityArray removeAllObjects];
        [self.selectedArray enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) {
            [self.cityArray addObject:obj[@"city"]];
        }];
        
        
        [pickerView reloadComponent:1];
        [pickerView selectRow:0 inComponent:1 animated:YES];
        
        
    }else if (component == 1) {
        if (self.selectedArray.count == 0) {
            self.selectedArray = [self.areaDataSource firstObject][@"cities"];
        }
        
    }else{
    }
    
    [self refreshSelectAreaData];
}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{
    
    for(UIView *singleLine in pickerView.subviews)
    {
        if (singleLine.frame.size.height < 1)
        {
            singleLine.backgroundColor =[UIColor grayColor];
        }
    }
    NSString *text;
    if (component == 0) {
        text =  self.provinceArray[row];
    }else if (component == 1){
        text =  self.cityArray[row];
    }else{
        
    }
    
    UILabel *label = [[UILabel alloc]init];
    label.textAlignment = 1;
    label.font = [UIFont systemFontOfSize:16];
    label.text = text;
    
    return label;
}


- (void)clickConfirmButton
{
    
    [self.delegate pickerArea:self selectProvince:self.selectProvince selectCity:self.selectCity];
    
    [super clickConfirmButton];
}


- (void)refreshSelectAreaData
{
    NSInteger provienceIndex = [self.pickerView selectedRowInComponent:0];
    NSInteger cityIndex = [self.pickerView selectedRowInComponent:1];
    
    self.selectProvince = self.provinceArray[provienceIndex];
    self.selectCity = self.cityArray[cityIndex];
    
    
}



- (NSArray *)areaDataSource
{
    if (!_areaDataSource) {
        NSString *path = [[NSBundle bundleForClass:[WXZPickCityView class]] pathForResource:@"area" ofType:@"plist"];
        _areaDataSource = [[NSArray alloc]initWithContentsOfFile:path];
    }
    return _areaDataSource;
}

- (NSMutableArray *)provinceArray
{
    if (!_provinceArray) {
        _provinceArray = [NSMutableArray array];
    }
    return _provinceArray;
}

- (NSMutableArray *)cityArray
{
    if (!_cityArray) {
        _cityArray = [NSMutableArray array];
    }
    return _cityArray;
}



- (NSMutableArray *)selectedArray
{
    if (!_selectedArray) {
        _selectedArray = [NSMutableArray array];
    }
    return _selectedArray;
}



@end

```

######(5)創(chuàng)建繼承于WXZBasePickView的單列選擇器WXZCustomPickView,可根據(jù)傳進(jìn)來的數(shù)組顯示相關(guān)的選擇內(nèi)容
.h聲明相關(guān)屬性和方法
```
#import "WXZBasePickView.h"

@class WXZCustomPickView;

@protocol  CustomPickViewDelegate<NSObject>
- (void)customPickView:(WXZCustomPickView *)customPickView selectedTitle:(NSString *)selectedTitle;
@end

@interface WXZCustomPickView :WXZBasePickView

@property (nonatomic, strong)NSMutableArray *dataArray;
@property(nonatomic, copy)NSString *defalutSelectRowStr;
@property(nonatomic, weak)id <CustomPickViewDelegate>delegate;
@end
```
.m實(shí)現(xiàn)相關(guān)方法
```
#import "WXZCustomPickView.h"
@interface WXZCustomPickView()<UIPickerViewDataSource, UIPickerViewDelegate>
/** 1.選中的字符串 */
@property (nonatomic, strong, nullable)NSString *selectedTitle;

@end

@implementation WXZCustomPickView

 
- (void)initPickView
{
    [super initPickView];
    
    _dataArray=[NSMutableArray mutableCopy];
 
  
    
    [self.pickerView setDelegate:self];
    [self.pickerView setDataSource:self];
    
    
    
    
}

-(void)setDefalutSelectRowStr:(NSString *)defalutSelectRowStr{
    _defalutSelectRowStr=defalutSelectRowStr;
    
    for (NSInteger i = 0; i<_dataArray.count; i++) {
        
        
        if ([_dataArray[i] isEqualToString:_defalutSelectRowStr]) {
            [self.pickerView reloadAllComponents];
            [self.pickerView selectRow:i inComponent:0 animated:NO];
            
        }
    }
}


- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    return self.dataArray.count;
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    return 36;
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
    
    return self.frame.size.width;
   
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    self.selectedTitle = self.dataArray[row];
}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{
    
    for(UIView *singleLine in pickerView.subviews)
    {
        if (singleLine.frame.size.height < 1)
        {
            singleLine.backgroundColor =[UIColor grayColor];
        }
    }
 
    UILabel *label = [[UILabel alloc]init];
    label.font=[UIFont systemFontOfSize:16];
    label.textAlignment = 1;
  
    label.text=self.dataArray[row];
    
        return label;
    
    
    
}
#pragma mark -點(diǎn)擊確定按鈕
- (void)clickConfirmButton
{
    [self.delegate customPickView:self selectedTitle:self.selectedTitle];
 
    [super clickConfirmButton];
}


- (void)setDataArray:(NSMutableArray *)dataArray
{
    _dataArray = dataArray;
    _selectedTitle = dataArray.firstObject;
    [self.pickerView reloadAllComponents];
    
}



@end
```
這樣,幾種類型的選擇器我們都定義好了,在需要選擇器的地方,根據(jù)需求創(chuàng)建相應(yīng)的選擇器即可。

###四、如何使用已創(chuàng)建好的自定義選擇器

引入自定義好的選擇器,聲明相關(guān)屬性,簽相關(guān)協(xié)議
```
#import "ViewController.h"
#import "WXZPickDateView.h"
#import "WXZPickAreaView.h"
#import "WXZPickTimeView.h"
#import "WXZCustomPickView.h"
@interface ViewController ()<PickerDateViewDelegate,PickerAreaViewDelegate,PickTimeViewDelegate,CustomPickViewDelegate>{
    UIButton *dateButton;
    UIButton *selectAreabutton;
    UIButton *selectTimeButton;
    UIButton *singlePickViewSelectButton;
    BOOL isShowDay;//是否顯示日信息
}

@end
```
創(chuàng)建相應(yīng)的按鈕,觸發(fā)相應(yīng)的選擇器
```
- (void)viewDidLoad {
    [super viewDidLoad];
 
    dateButton=[UIButton buttonWithType:UIButtonTypeCustom];
    dateButton.frame=CGRectMake(100, 100, 100, 50);
    [dateButton setTitle:@"選擇日期" forState:UIControlStateNormal];
    [self.view addSubview:dateButton];
    [dateButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [dateButton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
    dateButton.tag = 1000;
    
      selectAreabutton=[UIButton buttonWithType:UIButtonTypeCustom];
    selectAreabutton.frame=CGRectMake(100, 200, 100, 50);
    [selectAreabutton setTitle:@"選擇地區(qū)" forState:UIControlStateNormal];
    [self.view addSubview:selectAreabutton];
    [selectAreabutton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [selectAreabutton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
    selectAreabutton.tag = 1001;
    selectTimeButton=[UIButton buttonWithType:UIButtonTypeCustom];
    selectTimeButton.frame=CGRectMake(100, 300, 100, 50);
    [selectTimeButton setTitle:@"選擇時間" forState:UIControlStateNormal];
    [self.view addSubview:selectTimeButton];
    [selectTimeButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [selectTimeButton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
    selectTimeButton.tag = 1002;
    
    singlePickViewSelectButton=[UIButton buttonWithType:UIButtonTypeCustom];
    singlePickViewSelectButton.frame=CGRectMake(100, 400, 100, 50);
    [singlePickViewSelectButton setTitle:@"單個數(shù)據(jù)選擇器" forState:UIControlStateNormal];
    [self.view addSubview:singlePickViewSelectButton];
    [singlePickViewSelectButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [singlePickViewSelectButton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
    singlePickViewSelectButton.tag = 1003;
 
}
```
按鈕的點(diǎn)擊事件:
```
-(void)pickViewSelect:(UIButton *)button{
    if (button.tag==1000) {
        
           WXZPickDateView *pickerDate = [[WXZPickDateView alloc]init];
    
            
            [pickerDate setIsAddYetSelect:YES];//是否顯示至今選項(xiàng)
            [pickerDate setIsShowDay:YES];//是否顯示日信息
            [pickerDate setDefaultTSelectYear:2007 defaultSelectMonth:4 defaultSelectDay:1];//設(shè)定默認(rèn)顯示的日期
            [pickerDate setValidTime:2010];
     
            [pickerDate setDelegate:self];
   
           [pickerDate show];
    }else if (button.tag==1001){
        WXZPickAreaView *pickerArea = [[WXZPickAreaView alloc]init];
  
        [pickerArea setDelegate:self];
        
        [pickerArea setDefaultCity:@"上海" DefaultProvience:@"上海"];
 
        [pickerArea show];
        [self.view endEditing:YES];
    }else if (button.tag==1002){
        WXZPickTimeView *pickerArea = [[WXZPickTimeView alloc]init];
        
        [pickerArea setDelegate:self];
        
        [pickerArea setDefaultHour:14 defaultMinute:20];
        
        [pickerArea show];
        [self.view endEditing:YES];
    }else{
        NSMutableArray *arrayData = [NSMutableArray arrayWithObjects:@"2k以下",@"2k-5k",@"5k-10k",@"10k-15k",@"15k-25k",@"25k-50k",@"50k以上", nil];
        
        WXZCustomPickView *pickerSingle = [[WXZCustomPickView alloc]init];
 
        [pickerSingle setDataArray:arrayData];
        [pickerSingle setDefalutSelectRowStr:arrayData[0]];
 
        
        [pickerSingle setDelegate:self];
        
        [pickerSingle show];
        [self.view endEditing:YES];
   
    }
}
```
選擇器的代理方法
```
-(void)pickerDateView:(WXZBasePickView *)pickerDateView selectYear:(NSInteger)year selectMonth:(NSInteger)month selectDay:(NSInteger)day{
    NSLog(@"選擇的日期是:%ld %ld %ld",year,month,day);
    if (isShowDay==YES) {
        [dateButton setTitle:[NSString stringWithFormat:@"%ld年 %ld月 %ld日",year,month,day] forState:UIControlStateNormal];
    }else{
        [dateButton setTitle:[NSString stringWithFormat:@"%ld年 %ld月",year,month] forState:UIControlStateNormal];
    }
    
}

-(void)pickerArea:(WXZPickAreaView *)pickerArea selectProvince:(NSString *)province selectCity:(NSString *)city{
    NSLog(@"省市的選擇%@ %@",province,city);
    [selectAreabutton setTitle:[NSString stringWithFormat:@"%@%@",province,city] forState:UIControlStateNormal];
}

-(void)customPickView:(WXZCustomPickView *)customPickView selectedTitle:(NSString *)selectedTitle{
    NSLog(@"選擇%@",selectedTitle);
    [singlePickViewSelectButton setTitle:selectedTitle forState:UIControlStateNormal];
}
-(void)pickerTimeView:(WXZPickTimeView *)pickerTimeView selectHour:(NSInteger)hour selectMinute:(NSInteger)minute{
    NSLog(@"選擇的時間:%ld %ld",hour,minute);
    [selectTimeButton setTitle:[NSString stringWithFormat:@"%ld時 %ld分",hour,minute] forState:UIControlStateNormal];
}
```
最后,看看效果圖:

![選擇器demo效果圖](http://upload-images.jianshu.io/upload_images/972702-44b941b588bc4261.gif?imageMogr2/auto-orient/strip)

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

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

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