选择器,我想大家都不陌生,当需要用户去选择某些范围值内的一个固定值时,我们会采用选择器的方式。选择器可以直观的提示用户选择的值范围、统一信息的填写格式,同时也方便用户快速的进行选择,比如对于性别,正常情况下就只有男女两种情况,那这时候用一个选择器给用户进行选择的话,可以避免错误数据的输入,也更方便用户去填写。再比如需要获取用户的生日信息时,采用选择器的方式可以统一生日的格式,如果让用户自行输入的话,可能会出现各种各样的生日信息格式,不利于数据的存储,但是采用选择器的方式的话,用户可找到对应的日期进行选择即可。
一、为选择器创建Model
Model的形式主要是在选择器每一列的各个属性,下面以时间选择器为例子
@interface DateModel : NSObject
@property (nonatomic, retain) NSString *year;
@property (nonatomic, retain) NSString *month;
@property (nonatomic, retain) NSString *day;
@property (nonatomic, retain) NSString *hour;
@property (nonatomic, retain) NSString *minute;
- (id)initWithDate:(NSDate *)date
{
self = [super init];
if (self) {
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"yyyyMMddHHmm"];
NSString *dateString = [formatter stringFromDate:date];
self.year = [dateString substringWithRange:NSMakeRange(0, 4)];
self.month = [dateString substringWithRange:NSMakeRange(4, 2)];
self.day = [dateString substringWithRange:NSMakeRange(6, 2)];
self.hour = [dateString substringWithRange:NSMakeRange(8, 2)];
self.minute = [dateString substringWithRange:NSMakeRange(10, 2)];
}
return self;
}
@end
@end
二、实现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 ;
三、实现自定义的PickerView
下面以我自己封装的自定义PickerView为例子
@interface YTDatePick(){
/**
* 记录位置
*
*/
NSInteger yearIndex;
NSInteger monthIndex;
NSInteger dayIndex;
NSInteger hourIndex;
NSInteger minuteIndex;
NSArray *_indexArray;
}
@property (nonatomic, assign) BOOL isMySelect;
@end
@interface NSNumber (StringValue)
//@property (nonatomic, copy)NSString *string;
@end
@implementation NSNumber (StringValue)
- (NSString *)string{
if (self.integerValue >= 10) {
return [NSString stringWithFormat:@"%@", self];
}else{
return [NSString stringWithFormat:@"0%@", self];
}
}
@end
@interface MyPickViews: UIPickerView<UIPickerViewDelegate,UIPickerViewDataSource>
- (void)showPickViewWithFrame:(CGRect )frame
delegate:(id)delegate
supView:(UIView *)supView
numberOfRowsInComponent:(NSInteger(^)(NSInteger component))numberOfRowsInComponent
titleForRow:(UIView *(^)(NSInteger row, NSInteger component))titleForRow
didSelectRow:(void(^)(NSInteger row, NSInteger component))didSelectRow;
@property (nonatomic, copy)NSInteger(^numberOfRowsInComponent)(NSInteger component);
@property (nonatomic, copy)UIView *(^titleForRow)(NSInteger row, NSInteger component);
@property (nonatomic, copy)void(^didSelectRow)(NSInteger row, NSInteger component);
@end
@implementation MyPickViews
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
- (void)showPickViewWithFrame:(CGRect)frame delegate:(id)delegate supView:(UIView *)supView numberOfRowsInComponent:(NSInteger (^)(NSInteger ))numberOfRowsInComponent titleForRow:(UIView *(^)(NSInteger, NSInteger))titleForRow didSelectRow:(void (^)(NSInteger, NSInteger))didSelectRow{
self.delegate = self;
self.dataSource = self;
self.frame = frame;
if ([supView.subviews containsObject:self]) {
}else {
[supView addSubview:self];
}
self.numberOfRowsInComponent = numberOfRowsInComponent;
self.titleForRow = titleForRow;
self.didSelectRow = didSelectRow;
NSLog(@"%@", self.titleForRow);
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
return 50;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
if (self.numberOfRowsInComponent) {
return self.numberOfRowsInComponent(component);
}else{
return 0;
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
self.didSelectRow(row , component);
}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
[pickerView.subviews[1] setBackgroundColor:kColorNAVI_BULE];
[pickerView.subviews[2] setBackgroundColor:kColorNAVI_BULE];
return self.titleForRow(row, component);
}
@end
static void(^dayClickSureBlock)(id, id, id);
@interface YTDatePick ()
@property (nonatomic, strong)MyPickViews *firstTable, *secondTable, *thirdTable;
@property (nonatomic, assign)NSInteger fistSelect, secSelect,thirdSelect;
@property (nonatomic, strong)NSArray *dataArr;
@end
@implementation YTDatePick
- (UIPickerView *)firstTable{
if (!_firstTable) {
self.firstTable = [MyPickViews new];
}
return _firstTable;
}
- (UIPickerView *)secondTable{
if (!_secondTable) {
self.secondTable = [MyPickViews new];
}
return _secondTable;
}
- (UIPickerView *)thirdTable{
if (!_thirdTable) {
self.thirdTable = [MyPickViews new];
}
return _thirdTable;
}
- (id)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
//获取当前日期,储存当前时间位置
_indexArray = [self getNowDate:self.ScrollToDate];
self.fistSelect = (int)[_indexArray[0] integerValue];
self.secSelect = (int)[_indexArray[1] integerValue];
self.thirdSelect = (int)[_indexArray[2] integerValue];
[self configuesubViews];
//网络请求方法
_isMySelect = YES;
[self networkWithURL:nil];
[self addObserver:self forKeyPath:@"fistSelect" options:(NSKeyValueObservingOptionNew) context:nil];
[self addObserver:self forKeyPath:@"secSelect" options:(NSKeyValueObservingOptionNew) context:nil];
[self addObserver:self forKeyPath:@"thirdSelect" options:(NSKeyValueObservingOptionNew) context:nil];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
[self networkWithURL:nil];
}
+ (void)showPickWithMakeSure:(void (^)(id, id, id))selectArea{
dayClickSureBlock = selectArea;
YTDatePick *pick = [Window viewWithTag:999];
if (!pick) {
pick = [[YTDatePick alloc] initWithFrame:CGRectMake(0, 0, Window_Root.width, Window_Root.height)];
pick.tag = 999;
[Window addSubview:pick];
}
else{
// pick.hidden = NO;
[pick removeFromSuperview];
}
}
- (void)networkWithURL:(NSString *)urlStr{
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"daysList"];
NSFileManager *manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:path]) {
NSArray *array = [NSArray arrayWithContentsOfFile:path];
[self handleDataWithDic:array];
//获取当前日期,储存当前时间位置
_indexArray = [self getNowDate:self.ScrollToDate];
NSLog(@"++++%d", (int)[_indexArray[0] integerValue]);
NSLog(@"++++%d", (int)[_indexArray[1] integerValue]);
NSLog(@"++++%d", (int)[_indexArray[2] integerValue]);
//调整为现在的时间
if (_isMySelect) {
_isMySelect = NO;
[_firstTable selectRow:(int)[_indexArray[0] integerValue] inComponent:0 animated:YES];
[_secondTable selectRow:(int)[_indexArray[1] integerValue] inComponent:0 animated:YES];
[_thirdTable selectRow:(int)[_indexArray[2] integerValue] inComponent:0 animated:YES];
}
}else{
[self daysWithPath:path];
}
}
bool LeepYear(int year){
if (year % 100 == 0 ) {
if (year % 400 == 0) {
return 1;
}
return 0;
}else if (year % 4 == 0){
return 1;
}else{
return 0;
}
}
- (void)daysWithPath:(NSString *)path{
//年数组
NSMutableArray *yearArray = [@[] mutableCopy];
//设置年开始时间和结束年
for (int i = UUPICKER_MINDATE; i <= UUPICKER_MAXDATE; i ++) {
[yearArray addObject:@(i)];
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableArray *dataSource = [@[] mutableCopy];
for (NSNumber *year in yearArray) {
NSArray *temArray = @[@31, LeepYear(year.intValue) ? @29 : @28, @31, @30, @31, @30, @31, @31, @30, @31, @30, @31];
NSMutableArray *monthArray = [@[] mutableCopy];
for (int i = 1; i < 13; i ++) {
NSMutableArray *daysArray = [@[] mutableCopy];
for (int j = 1; j <= [temArray[i - 1] integerValue]; j ++) {
@autoreleasepool {
[daysArray addObject:@(j)];
}
}
@autoreleasepool {
NSDictionary *dic = @{@"month":@(i), @"daysList": daysArray};
[monthArray addObject:dic];
}
}
[dataSource addObject:@{@"year" : year, @"monthList":monthArray}];
}
[dataSource writeToFile:path atomically:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[self handleDataWithDic:dataSource];
[_firstTable reloadAllComponents];
[_secondTable reloadAllComponents];
[_thirdTable reloadAllComponents];
//获取当前日期,储存当前时间位置
_indexArray = [self getNowDate:self.ScrollToDate];
NSLog(@"++++%d", (int)[_indexArray[0] integerValue]);
NSLog(@"++++%d", (int)[_indexArray[1] integerValue]);
NSLog(@"++++%d", (int)[_indexArray[2] integerValue]);
if (_isMySelect) {
_isMySelect = NO;
[_firstTable selectRow:(int)[_indexArray[0] integerValue] inComponent:0 animated:YES];
[_secondTable selectRow:(int)[_indexArray[1] integerValue] inComponent:0 animated:YES];
[_thirdTable selectRow:(int)[_indexArray[2] integerValue] inComponent:0 animated:YES];
}
});
});
}
- (void)handleDataWithDic:(NSArray *)array{
self.dataArr = [NSMutableArray arrayWithArray:array];
[self.firstTable showPickViewWithFrame:CGRectMake(25, Window_Root.height - 220, Window_Root.width / 3.0 - 35, 150) delegate:self supView:self numberOfRowsInComponent:^NSInteger(NSInteger component) {
return self.dataArr.count;
} titleForRow:^UIView *(NSInteger row, NSInteger component) {
NSDictionary *model = self.dataArr[row];
UILabel *label = [[UILabel alloc] init];
label.text = [NSString stringWithFormat:@"%@年", model[@"year"]];
label.textAlignment = NSTextAlignmentCenter;
return label;
} didSelectRow:^(NSInteger row, NSInteger component) {
self.fistSelect = row;
}];
[self.secondTable showPickViewWithFrame:CGRectMake(Window_Root.width / 3.0 + 15, Window_Root.height - 220, Window_Root.width / 3.0 - 35, 150) delegate:self supView:self numberOfRowsInComponent:^NSInteger(NSInteger component) {
return 12;
} titleForRow:^UIView *(NSInteger row, NSInteger component) {
UILabel *label = [[UILabel alloc] init];
label.text = [NSString stringWithFormat:@"%@月",@(row + 1).string];
label.textAlignment = NSTextAlignmentCenter;
return label;
} didSelectRow:^(NSInteger row, NSInteger component) {
self.secSelect = row;
}];
[self.thirdTable showPickViewWithFrame:CGRectMake(Window_Root.width / 3.0 * 2 , Window_Root.height - 220, Window_Root.width / 3.0 - 35, 150) delegate:self supView:self numberOfRowsInComponent:^NSInteger(NSInteger component) {
NSArray *monthDic = self.dataArr[self.fistSelect][@"monthList"];
NSArray *dayList = monthDic[self.secSelect][@"daysList"];
return dayList.count;
} titleForRow:^UIView *(NSInteger row, NSInteger component) {
NSArray *monthDic = self.dataArr[self.fistSelect][@"monthList"];
NSArray *dayList = monthDic[self.secSelect][@"daysList"];
UILabel *label = [[UILabel alloc] init];
label.text = [NSString stringWithFormat:@"%@日", ((NSNumber *)dayList[row]).string];
label.textAlignment = NSTextAlignmentCenter;
return label;
} didSelectRow:^(NSInteger row, NSInteger component) {
}];
}
- (void)configuesubViews{
UIView *back = [[UIView alloc] initWithFrame:CGRectMake(20, Window_Root.height - 240, Window_Root.width - 50, 168)];
back.backgroundColor = [UIColor whiteColor];
back.layer.cornerRadius = 3;
back.clipsToBounds = YES;
[self addSubview:back];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, Window_Root.width-50, 40)];
label.textAlignment = NSTextAlignmentCenter;
label.text = @"选择时间";
label.font = [UIFont systemFontOfSize:18.0];
[back addSubview:label];
[self createButtonWithFrame:CGRectMake(20, self.bounds.size.height - 60, self.bounds.size.width / 2 - 30, 42) title:@"取 消" action:@selector(cancleClick)];
[self createButtonWithFrame:CGRectMake(self.bounds.size.width / 2 , self.bounds.size.height - 60, self.bounds.size.width / 2 - 30, 42) title:@"确 定" action:@selector(makeSure)];
}
- (void)createButtonWithFrame:(CGRect )rect title:(NSString *)title action:(SEL)acrion{
UIButton *cancleBtn = [UIButton buttonWithType:UIButtonTypeSystem];
cancleBtn.frame = rect;
[cancleBtn setTitle:title forState:(UIControlStateNormal)];
cancleBtn.backgroundColor = [UIColor whiteColor];
[cancleBtn setTitleColor:kColorNAVI_BULE forState:(UIControlStateNormal)];
cancleBtn.layer.cornerRadius = 3;
cancleBtn.clipsToBounds = YES;
[cancleBtn addTarget:self action:acrion forControlEvents:(UIControlEventTouchUpInside)];
[self addSubview:cancleBtn];
}
/**
* 取消
*/
- (void)cancleClick{
YTDatePick *pick = [Window viewWithTag:999];
// pick.hidden = YES;
[pick removeFromSuperview];
[[NSNotificationCenter defaultCenter] postNotificationName:@"setInfor" object:nil];
}
/**
* 确定
*/
- (void)makeSure{
NSString *year = self.dataArr[self.fistSelect][@"year"];
NSArray *monthDic = self.dataArr[self.fistSelect][@"monthList"];
NSArray *dayList = monthDic[self.secSelect][@"daysList"];
NSString *month = [NSString stringWithFormat:@"%ld", (long)[self.secondTable selectedRowInComponent:0] + 1];
NSString *day = dayList[[self.thirdTable selectedRowInComponent:0]];
dayClickSureBlock(@(year.integerValue).string, @(month.integerValue).string, @(day.integerValue).string);
NSLog(@"%@%@%@", @(year.integerValue).string, @(month.integerValue).string, @(day.integerValue).string);
[self cancleClick];
[[NSNotificationCenter defaultCenter] postNotificationName:@"setCancleValueChanges" object:nil];
}
//获取当前时间解析及位置
- (NSArray *)getNowDate:(NSDate *)date
{
NSDate *dateShow;
if (date) {
dateShow = date;
}else{
dateShow = [NSDate date];
}
YTDatePicker_DateModel *model = [[YTDatePicker_DateModel alloc]initWithDate:dateShow];
yearIndex = [model.year intValue]-UUPICKER_MINDATE;
monthIndex = [model.month intValue]-1;
dayIndex = [model.day intValue]-1;
NSNumber *year = [NSNumber numberWithInteger:yearIndex];
NSNumber *month = [NSNumber numberWithInteger:monthIndex];
NSNumber *day = [NSNumber numberWithInteger:dayIndex];
return @[year,month,day];
}
@end
参考博客
Apple开发者中心-Picker
iOS自定义日期、时间、城市选择器
菜鸟教程-IOS选择器