美文网首页
iOS 用UIPickerView自定义日期选择器(仿UIDat

iOS 用UIPickerView自定义日期选择器(仿UIDat

作者: IOSMan | 来源:发表于2019-08-01 18:39 被阅读0次

    UIDatePicker只有这四种模式:

    typedef NS_ENUM(NSInteger, UIDatePickerMode) {
        UIDatePickerModeTime,           // Displays hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. 6 | 53 | PM)
        UIDatePickerModeDate,           // Displays month, day, and year depending on the locale setting (e.g. November | 15 | 2007)
        UIDatePickerModeDateAndTime,    // Displays date, hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. Wed Nov 15 | 6 | 53 | PM)
        UIDatePickerModeCountDownTimer, // Displays hour and minute (e.g. 1 | 53)
    }
    

    效果图:
    只显示日期小时


    只显示日期小时

    只显示日期小时分钟


    只显示日期小时分钟
    只显示日期小时半点
    只显示日期小时半点

    如果只显示日期,小时,不显示分钟就得自定义,自定义当然是用UIPickerView,UIPickerView和tableview用法类似,必须实现两个DataSource方法

    @protocol UIPickerViewDataSource<NSObject>
    @required
    
    // returns the number of 'columns' to display.
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
    
    // returns the # of rows in each component..
    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
    

    介绍一下

    @protocol UIPickerViewDelegate<NSObject>
    @optional
    
    // 指定每个列的宽
    - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component 
    
    //指定每一列的行号
    - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component 
    
    //返回指定列指定行的字符串(一般数据源是一个二维数组)
    - (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component __TVOS_PROHIBITED;
    
    //返回指定列指定行的格式化字符串
    - (nullable NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED; // attributed title is favored if both methods are implemented
    
    //返回指定列指定行的view
    - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view __TVOS_PROHIBITED;
    
    //只要滚动UIPickerView就会调用这个方法,可以通过这个方法拿到滚动的数据,还可以在重组数据,滚动到特定位置对数据进行刷新
    - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component __TVOS_PROHIBITED;
    

    自定义日期选择器的难点是组织数据和滚动时限制数据的显示,重新组织数据
    在viewModel中组织好几个数据模型
    日期:

    #pragma mark - 日期数据源方法
    - (NSMutableArray *)setUpDataStartDate:(NSDate *)startDate endDate:(NSDate *)endDate {
        
    //    如果现在是晚上23:30以后那么日期要加30minute
        if ([self nowHourEqual23] && [self nowMinuteBig30] && self.dateType == D_YearMouthDayHourHalfMinute) {
            startDate = [NSDate dateWithTimeIntervalSince1970:([NSDate date].timeIntervalSince1970+60*30)];
        }
        
        NSTimeInterval timeInterval = [endDate timeIntervalSinceDate:startDate];
        if (timeInterval < 0) {
            return nil;
        }
        
        //    计算开始结束日期之间相差几个月
        NSInteger monthInterval;
        
        NSDateComponents *startComponents = [startDate getDateComponents];
        NSDateComponents *endComponents = [endDate getDateComponents];
        
        NSInteger startYear = startComponents.year;
        NSInteger endYear = endComponents.year;
        
        NSInteger startMonth = startComponents.month;
        NSInteger endMonth = endComponents.month;
        
        monthInterval = (endYear - startYear) * 12 + (endMonth - startMonth) + 1;
        
        
        NSMutableArray *dateArray = [NSMutableArray new];
        
        
        for (int i = 0; i < monthInterval; i++) {
            
            
            NSDateComponents *newComponent = [NSDateComponents new];
            NSInteger nowYear = startYear + (startMonth + i)/12;
            newComponent.year = nowYear;
            
            NSInteger monthYu = (startMonth + i) % 12;
            NSInteger nowMonth = monthYu ? monthYu : 12;
            newComponent.month = nowMonth;
            newComponent.day = 1;
            
            NSDate *newDate = [[NSCalendar currentCalendar]dateFromComponents:newComponent];
            
            //        本月第一天是周几
    //        NSInteger weekFirstDay = [newDate getFirstWeekInMonth];
            
            
            //        添加有数据的数据模型
            NSInteger daysMonth = [newDate getDayNumOfMouth];
            
            for (int k = 1; k <= daysMonth ; k++) {
    
                if (i == 0) {
                    if (k < startComponents.day) {
                        continue;
                    }
                }
                
                NSString *dateStr = [NSString stringWithFormat:@"%d年%d月%d日",nowYear,nowMonth,k];
                
                [dateArray addObject:dateStr];
            }
            
        }
        
        return dateArray;
    }
    

    其他数据源方法类似,根据定义的数据模型可以随意组合成各种各样的日期选择器。

    显示半点的逻辑有点复杂:
    如果是分钟只显示半点和整点,也就是显示0和30。根据当前时间,就要判断以下几点:
    1.当前日期,时间的分钟数>0且<30那么分钟只显示30
    2.如果大于30,那么小时数也要+1
    3.如果小时数+1的时候是23点,那么日期天数要+1

    初始化加载数据源的时候需要判断,滚动的时候也要判断
    只有当前日期(今天)有这个判断,其他日期不会

    用法:

        CustomDatePickerView *pickerV = [[CustomDatePickerView alloc]initWithFrame:CGRectMake(0, self.view.bounds.size.height-400, self.view.bounds.size.width, 400) withType:D_MouthDayHour];
    

    初始化的时候要指定类型

    typedef enum : NSUInteger {
        D_YearMouthDayHourHalfMinute,//日期,小时,半点
        D_MouthDayHour,//日期,小时
        D_MouthDayHourMinute,//日期,小时,分钟
    } DatePickerType;
    

    代码地址:https://github.com/D-james/D-CustomDatePickerView

    相关文章

      网友评论

          本文标题:iOS 用UIPickerView自定义日期选择器(仿UIDat

          本文链接:https://www.haomeiwen.com/subject/ffycdctx.html