iOS自定义日期、时间、城市选择器

选择器,我想大家都不陌生,当需要用户去选择某些范围值内的一个固定值时,我们会采用选择器的方式。选择器可以直观的提示用户选择的值范围、统一信息的填写格式,同时也方便用户快速的进行选择,比如对于性别,正常情况下就只有男女两种情况,那这时候用一个选择器给用户进行选择的话,可以避免错误数据的输入,也更方便用户去填写。再比如需要获取用户的生日信息时,采用选择器的方式可以统一生日的格式,如果让用户自行输入的话,可能会出现各种各样的生日信息格式,不利于数据的存储,但是采用选择器的方式的话,用户可找到对应的日期进行选择即可。

在iOS有专门的一个选择器类UIPickerView,进入UIPickerView的头文件,我们可以发现 UIPickerView直接继承了UIView,其事件处理通过代理方法完成,所以创建UIPickerView的时候记得签它的代理UIPickerViewDataSourceUIPickerViewDelegate。其实它和UITbleView有点像,不过UIPickerView还多了个列属性,UITbleView我们都很熟了,所以可以对比UITbleView的相关属性和代理方法来学习记忆UIPickerView。

一. UIPickerView的代理方法

(1)UIPickerViewDataSource对应的代理方法有(其代理方法必须要实现):

返回显示的列数

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

返回每一列中需要显示的行数

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

(2)UIPickerViewDelegate对应的代理方法(其代理方法根据需求进行选择性实现):

*返回每一列的宽度 *

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

返回每一列的高度

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

*返回UIPickerView控件中指定列的列表项的要显示的内容 *

- (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是系统帮我们封装好的一个时间日期选择器,继承于UIControl,UIDatePicker有一定的局限性,因为它只有四种显示样式:

UIDatePickerModeTime,          
UIDatePickerModeDate,          
UIDatePickerModeDateAndTime, 
UIDatePickerModeCountDownTimer, 

如果需求和这四种样式都不符合的话,那么就没办法使用UIDatePicker,比如当只需要显示年、月信息的时候,显然UIDatePicker没办法满足我们的需求,那这时我们只能通过UIPickerView来自定义自己想要的选择器。

三、UIPickerView的自定义使用

(1)创建基类继承于UIView的WXZBasePickView。

我们常见的选择器的样式是一个带透明背景色的view,底部是内容的选择器,有确定和取消按钮,大致如图:

选择器

所以我们创建一个基类view,这个view的样式如图所示样式,之后根据内容的差别创建基于该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;

/**
 *  创建视图,初始化视图时初始数据
 */
- (void)initPickView;

/**
 *  确认按钮的点击事件
 */
- (void)clickConfirmButton;

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

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


@end

在.m中实现相关方法

#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;
}
//初始化选择器内容,创建子类时需实现该父类方法
-(void)initPickView{
    
}
//点击确定按钮
- (void)clickConfirmButton
{
    [self disMiss];
}

//点击取消按钮
- (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];
        }];
    
}
//设置选择器的高度
- (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)、自定义一个日期选择器,可选择显示年、月或者年、月、日以及是否显示“至今”选项。

创建继承于我们自定义好的WXZBasePickView的日期选择器WXZPickDateView
.h声明相关属性和方法

#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;//是否增加至今的选项
@property(nonatomic, assign)BOOL isShowDay;//是否显示日
//设置默认显示的值
-(void)setDefaultTSelectYear:(NSInteger)defaultSelectYear defaultSelectMonth:(NSInteger)defaultSelectMonth defaultSelectDay:(NSInteger)defaultSelectDay;

@end
```
.m实现相关方法
 
```
#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];
    // 获取当前日期
    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) {
            //显示至今选项的话,需要比总共要显示的年份多返回一行
            return self.yearSum+1;
            
        }else{
          
           return self.yearSum;
        }
    }else if(component == 1) {
        NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
        if (yearSelected==_currentYear+1) {
            //至今选项的时候月份信息不返回
            return 0;
        }else{
            
            return 12;
        }
    }else {
        NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
        if (yearSelected==_currentYear+1) {
             //至今选项的时候日信息不返回
            return 0;
        }else{
        NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
        NSInteger monthSelected = [pickerView selectedRowInComponent:1] + 1;
        return  [self getDaysWithYear:yearSelected month:monthSelected];
        }
    }
    
    
}
//根据年、月判断日期天数
- (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)   创建继承于WXZBasePickView的时间选择器WXZPickTimeView。
.h声明属性及相关方法
```
#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实现相关方法
```
#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];
    // 获取当前日期
    NSDate* dt = [NSDate date];
    // 定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
    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)创建继承于WXZBasePickView的城市选择器WXZPickCityView。
.h声明相关属性和方法
```
#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 ;

/**设置默认的省市*/

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

```
.m实现相关方法
```
#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;//当前选中的数组

@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];
    
}

//设置默认显示的省市
-(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)创建继承于WXZBasePickView的单列选择器WXZCustomPickView,可根据传进来的数组显示相关的选择内容
.h声明相关属性和方法
```
#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实现相关方法
```
#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 -点击确定按钮
- (void)clickConfirmButton
{
    [self.delegate customPickView:self selectedTitle:self.selectedTitle];
 
    [super clickConfirmButton];
}


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



@end
```
这样,几种类型的选择器我们都定义好了,在需要选择器的地方,根据需求创建相应的选择器即可。

###四、如何使用已创建好的自定义选择器

引入自定义好的选择器,声明相关属性,签相关协议
```
#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
```
创建相应的按钮,触发相应的选择器
```
- (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:@"选择地区" 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:@"单个数据选择器" forState:UIControlStateNormal];
    [self.view addSubview:singlePickViewSelectButton];
    [singlePickViewSelectButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [singlePickViewSelectButton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
    singlePickViewSelectButton.tag = 1003;
 
}
```
按钮的点击事件:
```
-(void)pickViewSelect:(UIButton *)button{
    if (button.tag==1000) {
        
           WXZPickDateView *pickerDate = [[WXZPickDateView alloc]init];
    
            
            [pickerDate setIsAddYetSelect:YES];//是否显示至今选项
            [pickerDate setIsShowDay:YES];//是否显示日信息
            [pickerDate setDefaultTSelectYear:2007 defaultSelectMonth:4 defaultSelectDay:1];//设定默认显示的日期
            [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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容