iOS 年月日时分日期选择器

在做公司项目的时候,选择时间的时候有这样一个需求,可以选择年月日时分这个时间,分有5分钟的间隔,这样子系统的UIDatePickerView就不能用了,好吧,既然有这个需求,咱也不能说这个不能做,不能用UIDatePickerView自带的时间选择。 那就用UIPickerView来写。

Alt text

Alt text

控制器的调用

#import "ViewController.h"

#import "THDatePickerView.h"

@interface ViewController () <THDatePickerViewDelegate>
@property (weak, nonatomic) IBOutlet UILabel *timerLbl;
@property (weak, nonatomic) THDatePickerView *dateView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   // 创建
    THDatePickerView *dateView = [[THDatePickerView alloc] initWithFrame:self.view.bounds];
   // 设置代理
    dateView.delegate = self;
   // 设置标题
    dateView.title = @"请选择时间";
    [self.view addSubview:dateView];
    self.dateView = dateView;
}

// 显示
- (IBAction)timerBrnClick:(id)sender {
    [self.dateView show];
}

#pragma mark - THDatePickerViewDelegate
/**
 保存按钮代理方法
 
 @param timer 选择的数据
 */
- (void)datePickerViewSaveBtnClickDelegate:(NSString *)timer {
    NSLog(@"保存点击");
    self.timerLbl.text = timer;
}

/**
 取消按钮代理方法
 */
- (void)datePickerViewCancelBtnClickDelegate {
    NSLog(@"取消点击");
}

具体实现THDatePickerView.h文件

@protocol THDatePickerViewDelegate <NSObject>

/**
 保存按钮代理方法
 
 @param timer 选择的数据
 */
- (void)datePickerViewSaveBtnClickDelegate:(NSString *)timer;

/**
 取消按钮代理方法
 */
- (void)datePickerViewCancelBtnClickDelegate;

@end

@interface THDatePickerView : UIView

@property (copy, nonatomic) NSString *title;
@property (weak, nonatomic) id <THDatePickerViewDelegate> delegate;

/// 显示
- (void)show;

具体实现THDatePickerView.m文件

@property (strong, nonatomic) UIView *dataView; // 容器view
@property (strong, nonatomic) UIPickerView *pickerView; // 选择器
@property (strong, nonatomic) UIView *toolView; // 工具条
@property (strong, nonatomic) UILabel *titleLbl; // 标题

@property (strong, nonatomic) NSMutableArray *dataArray; // 数据源
@property (copy, nonatomic) NSString *selectStr; // 选中的时间


@property (strong, nonatomic) NSMutableArray *yearArr; // 年数组
@property (strong, nonatomic) NSMutableArray *monthArr; // 月数组
@property (strong, nonatomic) NSMutableArray *dayArr; // 日数组
@property (strong, nonatomic) NSMutableArray *hourArr; // 时数组
@property (strong, nonatomic) NSMutableArray *minuteArr; // 分数组
@property (strong, nonatomic) NSArray *timeArr; // 当前时间数组

@property (copy, nonatomic) NSString *year; // 选中年
@property (copy, nonatomic) NSString *month; //选中月
@property (copy, nonatomic) NSString *day; //选中日
@property (copy, nonatomic) NSString *hour; //选中时
@property (copy, nonatomic) NSString *minute; //选中分
- (void)show {
    [UIView animateWithDuration:0.25 animations:^{
        self.year = self.timeArr[0];
        self.month = self.timeArr[1];
        self.day = self.timeArr[2];
        self.hour = self.timeArr[3];
        self.minute = self.minuteArr[self.minuteArr.count / 2];
        
        CGRect frame = self.dataView.frame;
        frame.origin.y = self.frame.size.height - 300;
        self.dataView.frame = frame;
        
        self.hidden = NO;
    } completion:^(BOOL finished) {
        
        [self.pickerView selectRow:[self.yearArr indexOfObject:self.year] inComponent:0 animated:YES];
        /// 重新格式化转一下,是因为如果是09月/日/时,数据源是9月/日/时,就会出现崩溃
        [self.pickerView selectRow:[self.monthArr indexOfObject:[NSString stringWithFormat:@"%ld月", [self.month integerValue]]] inComponent:1 animated:YES];
        [self.pickerView selectRow:[self.dayArr indexOfObject:[NSString stringWithFormat:@"%ld日", [self.day integerValue]]] inComponent:2 animated:YES];
        [self.pickerView selectRow:[self.hourArr indexOfObject:[NSString stringWithFormat:@"%ld时", [self.hour integerValue]]] inComponent:3 animated:YES];
        [self.pickerView selectRow:self.minuteArr.count / 2 inComponent:4 animated:YES];
    }];
}

pragma mark - 点击方法

/// 保存按钮点击方法

- (void)saveBtnClick {
    NSLog(@"点击了保存");
    
    [UIView animateWithDuration:0.25 animations:^{
        
        CGRect frame = self.dataView.frame;
        frame.origin.y = self.frame.size.height;
        self.dataView.frame = frame;
        
    } completion:^(BOOL finished) {
        
        self.hidden = YES;
        NSInteger index = [self compareDate:[self.timeArr componentsJoinedByString:@","] withDate:[NSString stringWithFormat:@"%@,%@,%@,%@,%@", self.year, self.month, self.day, self.hour, self.minute]];
        switch (index) {
            case -1: {
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"面试时间小于当前时间,请重新选择" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
                [alert show];
            } break;
            case 0:
            case 1: {
                if (self.minute.length == 2) {
                    self.selectStr = [NSString stringWithFormat:@"%ld-%ld-%ld  %ld : 0%ld", [self.year integerValue], [self.month integerValue], [self.day integerValue], [self.hour integerValue], [self.minute integerValue]];
                } else {
                    self.selectStr = [NSString stringWithFormat:@"%ld-%ld-%ld  %ld : %ld", [self.year integerValue], [self.month integerValue], [self.day integerValue], [self.hour integerValue], [self.minute integerValue]];
                }
                if ([self.delegate respondsToSelector:@selector(datePickerViewSaveBtnClickDelegate:)]) {
                    [self.delegate datePickerViewSaveBtnClickDelegate:self.selectStr];
                }
            } break;
            default: break;
        }
    }];
    
}

/// 取消按钮点击方法

- (void)cancelBtnClick {
    NSLog(@"点击了取消");
    
    [UIView animateWithDuration:0.25 animations:^{
        
        CGRect frame = self.dataView.frame;
        frame.origin.y = self.frame.size.height;
        self.dataView.frame = frame;
        
    } completion:^(BOOL finished) {
        
        self.hidden = YES;
        if ([self.delegate respondsToSelector:@selector(datePickerViewCancelBtnClickDelegate)]) {
            [self.delegate datePickerViewCancelBtnClickDelegate];
        }
    }];
}

/// 点击背景消失

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    [self cancelBtnClick];
}

pragma mark - UIPickerViewDelegate and UIPickerViewDataSource

/// UIPickerView返回多少组

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

/// UIPickerView返回每组多少条数据

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

/// UIPickerView选择哪一行

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    switch (component) {
        case 0: { // 年
            if ([self.yearArr[row] integerValue] < [self.timeArr[component] integerValue]) {
                [pickerView selectRow:[self.dataArray[component] indexOfObject:self.timeArr[component]] inComponent:component animated:YES];
            } else {
                self.year = self.yearArr[row];
                [self.pickerView selectRow:[self.monthArr indexOfObject:self.timeArr[1]] inComponent:1 animated:YES];
                [self.pickerView selectRow:[self.dayArr indexOfObject:self.timeArr[2]] inComponent:2 animated:YES];
                [self.pickerView selectRow:[self.hourArr indexOfObject:self.timeArr[3]] inComponent:3 animated:YES];
            }
        } break;
        case 1: { // 月
            // 如果选择年大于当前年 就直接赋值月
            if ([self.year integerValue] > [self.timeArr[0] integerValue]) {
                self.month = self.monthArr[row];
            // 如果选择的年等于当前年,就判断月份
            } else if ([self.year integerValue] == [self.timeArr[0] integerValue]) {
                // 如果选择的月份小于当前月份 就刷新到当前月份
                if ([self.monthArr[row] integerValue] < [self.timeArr[component] integerValue]) {
                    [pickerView selectRow:[self.dataArray[component] indexOfObject:self.timeArr[component]] inComponent:component animated:YES];
                // 如果选择的月份大于当前月份,就直接赋值月份
                } else {
                    self.month = self.monthArr[row];
                }
            }
        } break;
        case 2: { // 日
            // 如果选择年大于当前年 就直接赋值日
            if ([self.year integerValue] > [self.timeArr[0] integerValue]) {
                self.day = self.dayArr[row];
                // 如果选择的年等于当前年,就判断月份
            } else if ([self.year integerValue] == [self.timeArr[0] integerValue]) {
                // 如果选择的月份大于当前月份 就直接复制
                if ([self.month integerValue] > [self.timeArr[1] integerValue]) {
                    self.day = self.dayArr[row];
                // 如果选择的月份等于当前月份,就判断日
                } else if ([self.month integerValue] == [self.timeArr[1] integerValue]) {
                    // 如果选择的日小于当前日,就刷新到当前日
                    if ([self.dayArr[row] integerValue] < [self.timeArr[component] integerValue]) {
                        [pickerView selectRow:[self.dataArray[component] indexOfObject:self.timeArr[component]] inComponent:component animated:YES];
                    // 如果选择的日大于当前日,就复制日
                    } else {
                        self.day = self.dayArr[row];
                    }
                }
            }
        } break;
        case 3: { // 时
            // 如果选择年大于当前年 就直接赋值时
            if ([self.year integerValue] > [self.timeArr[0] integerValue]) {
                self.hour = self.hourArr[row];
                // 如果选择的年等于当前年,就判断月份
            } else if ([self.year integerValue] == [self.timeArr[0] integerValue]) {
                // 如果选择的月份大于当前月份 就直接复制时
                if ([self.month integerValue] > [self.timeArr[1] integerValue]) {
                    self.hour = self.hourArr[row];
                    // 如果选择的月份等于当前月份,就判断日
                } else if ([self.month integerValue] == [self.timeArr[1] integerValue]) {
                    // 如果选择的日大于当前日,就直接复制时
                    if ([self.day integerValue] > [self.timeArr[2] integerValue]) {
                        self.hour = self.hourArr[row];
                    // 如果选择的日等于当前日,就判断时
                    } else if ([self.day integerValue] == [self.timeArr[2] integerValue]) {
                        // 如果选择的时小于当前时,就刷新到当前时
                        if ([self.hourArr[row] integerValue] < [self.timeArr[3] integerValue]) {
                            [pickerView selectRow:[self.dataArray[component] indexOfObject:self.timeArr[component]] inComponent:component animated:YES];
                        // 如果选择的时大于当前时,就直接赋值
                        } else {
                            self.hour = self.hourArr[row];
                        }
                    }
                }
            }
        } break;
        case 4: { // 分
            // 如果选择年大于当前年 就直接赋值时
//            if ([self.year integerValue] > [self.timeArr[0] integerValue]) {
                self.minute = self.minuteArr[row];
//                // 如果选择的年等于当前年,就判断月份
//            } else if ([self.year integerValue] == [self.timeArr[0] integerValue]) {
//                // 如果选择的月份大于当前月份 就直接复制时
//                if ([self.month integerValue] > [self.timeArr[1] integerValue]) {
//                    self.minute = self.minuteArr[row];
//                    // 如果选择的月份等于当前月份,就判断日
//                } else if ([self.month integerValue] == [self.timeArr[1] integerValue]) {
//                    // 如果选择的日大于当前日,就直接复制时
//                    if ([self.day integerValue] > [self.timeArr[2] integerValue]) {
//                        self.minute = self.minuteArr[row];
//                        // 如果选择的日等于当前日,就判断时
//                    } else if ([self.day integerValue] == [self.timeArr[2] integerValue]) {
//                        // 如果选择的时大于当前时,就直接赋值
//                        if ([self.hour integerValue] > [self.timeArr[3] integerValue]) {
//                            self.minute = self.minuteArr[row];
//                        // 如果选择的时等于当前时,就判断分
//                        } else if ([self.hour integerValue] == [self.timeArr[3] integerValue]) {
//                            // 如果选择的分小于当前分,就刷新分
//                            if ([self.minuteArr[row] integerValue] < [self.timeArr[4] integerValue]) {
//                                [pickerView selectRow:[self.dataArray[component] indexOfObject:self.timeArr[component]] inComponent:component animated:YES];
//                            // 如果选择分大于当前分,就直接赋值
//                            } else {
//                                self.minute = self.minuteArr[row];
//                            }
//                        }
//                    }
//                }
//            }
        } break;
        default: break;
    }
}

/// UIPickerView返回每一行数据

- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    return  self.dataArray[component][row];
}

/// UIPickerView返回每一行的高度

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

/// UIPickerView返回每一行的View

-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
    UILabel *myView = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, self.frame.size.width, 44)];
    myView.font = [UIFont systemFontOfSize:15];
    myView.textAlignment = NSTextAlignmentCenter;
    myView.text = self.dataArray[component][row];
    return myView;
}

// 比较选择的时间是否小于当前时间

- (int)compareDate:(NSString *)date01 withDate:(NSString *)date02{
    int ci;
    NSDateFormatter *df = [[NSDateFormatter alloc]init];
    [df setDateFormat:@"yyyy年,MM月,dd日,HH时,mm分"];
    NSDate *dt1 = [[NSDate alloc] init];
    NSDate *dt2 = [[NSDate alloc] init];
    dt1 = [df dateFromString:date01];
    dt2 = [df dateFromString:date02];
    NSComparisonResult result = [dt1 compare:dt2];
    switch (result) {
            //date02比date01大
        case NSOrderedAscending: ci=1;break;
            //date02比date01小
        case NSOrderedDescending: ci=-1;break;
            //date02=date01
        case NSOrderedSame: ci=0;break;
        default: NSLog(@"erorr dates %@, %@", dt2, dt1);break;
    }
    return ci;
}

好了就这样子实现了。主要是时间选择的时候,判断年月日时的时候比较烦,分的话,因为获取的当前时间和self.minuteArr数组里面的时间不通。所以不做判断,但是代码就是这样子了。
欢迎来来我的github网址下来dome 如果觉得好麻烦请star

2018-3-12 更新

  1. 可以选择以前的时间
    2.支持自定义当前时间
    3.支持修改分钟时间间隔
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,192评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,858评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,517评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,148评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,162评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,905评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,537评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,439评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,956评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,083评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,218评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,899评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,565评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,093评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,201评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,539评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,215评论 2 358

推荐阅读更多精彩内容