自定义支持多种格式可控范围的时间选择器控件

支持四种格式,可控制可选时间范围,如下:

(1)年月日时分

(2)年月日

(3)月日时分

(4)时分

 

效果如下:

iPhone 5s

 

iPhone 6

 

iPhone 6 Plus

  

 

ViewController.h

 1 #import <UIKit/UIKit.h>
 2 #import "KMDatePicker.h"
 3 
 4 @interface ViewController : UIViewController <UITextFieldDelegate, KMDatePickerDelegate>
 5 @property (strong, nonatomic) UITextField *txtFCurrent;
 6 
 7 @property (strong, nonatomic) IBOutlet UITextField *txtFYearMonthDayHourMinute;
 8 @property (strong, nonatomic) IBOutlet UITextField *txtFMonthDayHourMinute;
 9 @property (strong, nonatomic) IBOutlet UITextField *txtFYearMonthDay;
10 @property (strong, nonatomic) IBOutlet UITextField *txtFHourMinute;
11 @property (strong, nonatomic) IBOutlet UITextField *txtFLimitedDate;
12 
13 @end 

ViewController.m

 1 #import "ViewController.h"
 2 #import "DateHelper.h"
 3 #import "NSDate+CalculateDay.h"
 4 
 5 @interface ViewController ()
 6 - (void)layoutUI;
 7 @end
 8 
 9 @implementation ViewController
10 
11 - (void)viewDidLoad {
12     [super viewDidLoad];
13     
14     [self layoutUI];
15 }
16 
17 - (void)didReceiveMemoryWarning {
18     [super didReceiveMemoryWarning];
19     // Dispose of any resources that can be recreated.
20 }
21 
22 - (void)layoutUI {
23     CGRect rect = [[UIScreen mainScreen] bounds];
24     rect = CGRectMake(0.0, 0.0, rect.size.width, 216.0);
25     //年月日时分
26     KMDatePicker *datePicker = [[KMDatePicker alloc]
27                                 initWithFrame:rect
28                                 delegate:self
29                                 datePickerStyle:KMDatePickerStyleYearMonthDayHourMinute];
30     _txtFYearMonthDayHourMinute.inputView = datePicker;
31     _txtFYearMonthDayHourMinute.delegate = self;
32     
33     //年月日
34     datePicker = [[KMDatePicker alloc]
35                   initWithFrame:rect
36                   delegate:self
37                   datePickerStyle:KMDatePickerStyleYearMonthDay];
38     _txtFYearMonthDay.inputView = datePicker;
39     _txtFYearMonthDay.delegate = self;
40     
41     //月日时分
42     datePicker = [[KMDatePicker alloc]
43                   initWithFrame:rect
44                   delegate:self
45                   datePickerStyle:KMDatePickerStyleMonthDayHourMinute];
46     _txtFMonthDayHourMinute.inputView = datePicker;
47     _txtFMonthDayHourMinute.delegate = self;
48     
49     //时分
50     datePicker = [[KMDatePicker alloc]
51                   initWithFrame:rect
52                   delegate:self
53                   datePickerStyle:KMDatePickerStyleHourMinute];
54     _txtFHourMinute.inputView = datePicker;
55     _txtFHourMinute.delegate = self;
56     
57     //年月日时分;限制时间范围
58     datePicker = [[KMDatePicker alloc]
59                   initWithFrame:rect
60                   delegate:self
61                   datePickerStyle:KMDatePickerStyleYearMonthDayHourMinute];
62     datePicker.minLimitedDate = [[DateHelper localeDate] km_addMonthAndDay:-24 days:0];
63     datePicker.maxLimitedDate = [datePicker.minLimitedDate km_addMonthAndDay:48 days:0];
64     _txtFLimitedDate.inputView = datePicker;
65     _txtFLimitedDate.delegate = self;
66 }
67 
68 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
69     [self.view endEditing:YES];
70 }
71 
72 #pragma mark - UITextFieldDelegate
73 - (void)textFieldDidBeginEditing:(UITextField *)textField {
74     _txtFCurrent = textField;
75 }
76 
77 #pragma mark - KMDatePickerDelegate
78 - (void)datePicker:(KMDatePicker *)datePicker didSelectDate:(KMDatePickerDateModel *)datePickerDate {
79     NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@ %@",
80                          datePickerDate.year,
81                          datePickerDate.month,
82                          datePickerDate.day,
83                          datePickerDate.hour,
84                          datePickerDate.minute,
85                          datePickerDate.weekdayName
86                          ];
87     _txtFCurrent.text = dateStr;
88 }
89 
90 @end 

Main.storyboard

 1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
 3     <dependencies>
 4         <deployment identifier="iOS"/>
 5         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
 6     </dependencies>
 7     <scenes>
 8         <!--View Controller-->
 9         <scene sceneID="tne-QT-ifu">
10             <objects>
11                 <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
12                     <layoutGuides>
13                         <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
14                         <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
15                     </layoutGuides>
16                     <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
17                         <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
18                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
19                         <subviews>
20                             <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="YearMonthDayHourMinute" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="RU4-aD-bI3">
21                                 <rect key="frame" x="180" y="58" width="240" height="30"/>
22                                 <animations/>
23                                 <constraints>
24                                     <constraint firstAttribute="width" constant="240" id="9Oi-OR-Ru9"/>
25                                     <constraint firstAttribute="height" constant="30" id="Wsa-Pd-EDg"/>
26                                 </constraints>
27                                 <fontDescription key="fontDescription" type="system" pointSize="14"/>
28                                 <textInputTraits key="textInputTraits"/>
29                             </textField>
30                             <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="MonthDayHourMinute" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="KFz-2Q-yIQ">
31                                 <rect key="frame" x="180" y="170" width="240" height="30"/>
32                                 <animations/>
33                                 <constraints>
34                                     <constraint firstAttribute="height" constant="30" id="Qxz-uf-Ngd"/>
35                                     <constraint firstAttribute="width" constant="240" id="pTd-xH-c6N"/>
36                                 </constraints>
37                                 <fontDescription key="fontDescription" type="system" pointSize="14"/>
38                                 <textInputTraits key="textInputTraits"/>
39                             </textField>
40                             <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="YearMonthDay" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="V6m-6E-ZuV">
41                                 <rect key="frame" x="180" y="113" width="240" height="30"/>
42                                 <animations/>
43                                 <constraints>
44                                     <constraint firstAttribute="height" constant="30" id="CzE-ap-TTQ"/>
45                                     <constraint firstAttribute="width" constant="240" id="eCi-kT-2tg"/>
46                                 </constraints>
47                                 <fontDescription key="fontDescription" type="system" pointSize="14"/>
48                                 <textInputTraits key="textInputTraits"/>
49                             </textField>
50                             <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="HourMinute" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Neu-Vj-fG0">
51                                 <rect key="frame" x="180" y="228" width="240" height="30"/>
52                                 <animations/>
53                                 <constraints>
54                                     <constraint firstAttribute="width" constant="240" id="XBx-GA-ad2"/>
55                                     <constraint firstAttribute="height" constant="30" id="tON-2M-EMP"/>
56                                 </constraints>
57                                 <fontDescription key="fontDescription" type="system" pointSize="14"/>
58                                 <textInputTraits key="textInputTraits"/>
59                             </textField>
60                             <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="LimitedDate" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vt1-Aj-i6Y">
61                                 <rect key="frame" x="180" y="280" width="240" height="30"/>
62                                 <animations/>
63                                 <constraints>
64                                     <constraint firstAttribute="height" constant="30" id="QSC-Me-tpx"/>
65                                     <constraint firstAttribute="width" constant="240" id="X0a-1i-Z2T"/>
66                                 </constraints>
67                                 <fontDescription key="fontDescription" type="system" pointSize="14"/>
68                                 <textInputTraits key="textInputTraits"/>
69                             </textField>
70                         </subviews>
71                         <animations/>
72                         <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
73                         <constraints>
74                             <constraint firstItem="Neu-Vj-fG0" firstAttribute="top" secondItem="KFz-2Q-yIQ" secondAttribute="bottom" constant="28" id="4Wp-rC-NJF"/>
75                             <constraint firstItem="RU4-aD-bI3" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="38" id="EU7-1f-tVl"/>
76                             <constraint firstItem="RU4-aD-bI3" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="FUG-e6-Qhi"/>
77                             <constraint firstItem="Neu-Vj-fG0" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="HRH-7N-oaY"/>
78                             <constraint firstItem="V6m-6E-ZuV" firstAttribute="top" secondItem="RU4-aD-bI3" secondAttribute="bottom" constant="25" id="Ind-TZ-Rzm"/>
79                             <constraint firstItem="V6m-6E-ZuV" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="JTW-zd-LlI"/>
80                             <constraint firstItem="KFz-2Q-yIQ" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="LpF-Jq-wwJ"/>
81                             <constraint firstItem="KFz-2Q-yIQ" firstAttribute="top" secondItem="V6m-6E-ZuV" secondAttribute="bottom" constant="27" id="TyY-DA-rn2"/>
82                             <constraint firstItem="vt1-Aj-i6Y" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="g0Z-bZ-p3g"/>
83                             <constraint firstItem="vt1-Aj-i6Y" firstAttribute="top" secondItem="Neu-Vj-fG0" secondAttribute="bottom" constant="22" id="tyA-YZ-slJ"/>
84                         </constraints>
85                     </view>
86                     <connections>
87                         <outlet property="txtFHourMinute" destination="Neu-Vj-fG0" id="wPd-UK-nh5"/>
88                         <outlet property="txtFLimitedDate" destination="vt1-Aj-i6Y" id="MzT-tx-thY"/>
89                         <outlet property="txtFMonthDayHourMinute" destination="KFz-2Q-yIQ" id="Hp6-Ve-tYI"/>
90                         <outlet property="txtFYearMonthDay" destination="V6m-6E-ZuV" id="0cJ-v8-xh3"/>
91                         <outlet property="txtFYearMonthDayHourMinute" destination="RU4-aD-bI3" id="neo-JQ-wV5"/>
92                     </connections>
93                 </viewController>
94                 <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
95             </objects>
96         </scene>
97     </scenes>
98 </document>
View Code 

NSDate+CalculateDay.h

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface NSDate (CalculateDay)
 4 
 5 /**
 6  *  获取对应月份的天数
 7  *
 8  *  @return 对应月份的天数
 9  */
10 - (NSUInteger)km_daysOfMonth;
11 
12 /**
13  *  获取对应年份的天数
14  *
15  *  @return 对应年份的天数
16  */
17 - (NSUInteger)km_daysOfYear;
18 
19 /**
20  *  获取对应月份的第一天时间
21  *
22  *  @return 对应月份的第一天时间
23  */
24 - (NSDate *)km_firstDayOfMonth;
25 
26 /**
27  *  获取对应月份的最后一天时间
28  *
29  *  @return 对应月份的最后一天时间
30  */
31 - (NSDate *)km_lastDayOfMonth;
32 
33 /**
34  *  根据月数和天数间隔,获取间隔后的时间
35  *
36  *  @param months 月数间隔
37  *  @param days   天数间隔
38  *
39  *  @return 间隔后的时间
40  */
41 - (NSDate *)km_addMonthAndDay:(NSUInteger)months days:(NSUInteger)days;
42 
43 /**
44  *  根据开始时间和结束时间,获取间隔的时间数组
45  *
46  *  @param toDate 结束时间
47  *
48  *  @return 间隔的时间数组(月数和天数;toDate-fromDate的比较值是有符号整数NSInteger,所以存在负数的可能)
49  */
50 - (NSArray *)km_monthAndDayBetweenTwoDates:(NSDate *)toDate;
51 
52 /**
53  *  获取对应周期的数字
54  *
55  *  @return 对应周期的数字(1:周日、2:周一、3:周二、4:周三、5:周四、6:周五、7:周六)
56  */
57 - (NSInteger)km_weekday;
58 
59 /**
60  *  根据地区标示符,获取对应周期的名称
61  *
62  *  @param isShortName      是否是短名称
63  *  @param localeIdentifier 地区标示符(中国:zh_CN、美国:en_US)
64  *
65  *  @return 对应周期的名称
66  */
67 - (NSString *)km_weekdayName:(BOOL)isShortName localeIdentifier:(NSString *)localeIdentifier;
68 
69 /**
70  *  获取对应周期的中文名称
71  *
72  *  @param isShortName 是否是短名称
73  *
74  *  @return 对应周期的中文名称(短名称:周日、周一、周二、周三、周四、周五、周六)(长名称:星期日、星期一、星期二、星期三、星期四、星期五、星期六)
75  */
76 - (NSString *)km_weekdayNameCN:(BOOL)isShortName;
77 
78 /**
79  *  获取对应周期的英文名称
80  *
81  *  @param isShortName 是否是短名称
82  *
83  *  @return 对应周期的英文名称(短名称:Sun、Mon、Tue、Wed、Thu、Fri、Sat)(长名称:Sunday、Monday、Tuesday、Wednesday、Thursday、Friday、Saturday)
84  */
85 - (NSString *)km_weekdayNameEN:(BOOL)isShortName;
86 
87 @end

NSDate+CalculateDay.m

  1 #import "NSDate+CalculateDay.h"
  2 
  3 @implementation NSDate (CalculateDay)
  4 
  5 - (NSUInteger)km_daysOfMonth {
  6     NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  7     NSRange range = [gregorian rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:self];
  8     return range.length;
  9 }
 10 
 11 - (NSUInteger)km_daysOfYear {
 12     NSUInteger days = 0;
 13     NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
 14     NSDateComponents *comps = [gregorian components:NSCalendarUnitYear fromDate:self];
 15     
 16     for (NSUInteger i=1; i<=12; i++) {
 17         [comps setMonth:i];
 18         days += [[gregorian dateFromComponents:comps] km_daysOfMonth];
 19     }
 20     return days;
 21 }
 22 
 23 - (NSDate *)km_firstDayOfMonth {
 24     NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
 25     unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth |  NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
 26     NSDateComponents *comps = [gregorian components:unitFlags fromDate:self];
 27     [comps setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // 使用UTC或GMT解决时区相差8小时的问题
 28     [comps setDay:1];
 29     
 30     return [gregorian dateFromComponents:comps];
 31 }
 32 
 33 - (NSDate *)km_lastDayOfMonth {
 34     NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
 35     unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth |  NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
 36     NSDateComponents *comps = [gregorian components:unitFlags fromDate:self];
 37     [comps setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // 使用UTC或GMT解决时区相差8小时的问题
 38     [comps setDay:[self km_daysOfMonth]];
 39     
 40     return [gregorian dateFromComponents:comps];
 41 }
 42 
 43 - (NSDate *)km_addMonthAndDay:(NSUInteger)months days:(NSUInteger)days {
 44     NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
 45     NSDateComponents *comps = [NSDateComponents new];
 46     [comps setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // 使用UTC或GMT解决时区相差8小时的问题
 47     [comps setMonth:months];
 48     [comps setDay:days];
 49     
 50     return [gregorian dateByAddingComponents:comps toDate:self options:0];
 51 }
 52 
 53 - (NSArray *)km_monthAndDayBetweenTwoDates:(NSDate *)toDate {
 54     NSMutableArray *mArrMonthAndDay = [[NSMutableArray alloc] initWithCapacity:2];
 55     NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
 56     unsigned unitFlags = NSCalendarUnitMonth |  NSCalendarUnitDay;
 57     NSDateComponents *comps = [gregorian components:unitFlags fromDate:self toDate:toDate options:0];
 58     
 59     [mArrMonthAndDay addObject:[NSString stringWithFormat:@"%ld", (long)[comps month]]];
 60     [mArrMonthAndDay addObject:[NSString stringWithFormat:@"%ld", (long)[comps day]]];
 61     return mArrMonthAndDay;
 62 }
 63 
 64 - (NSInteger)km_weekday {
 65     return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekday fromDate:self] weekday];
 66 }
 67 
 68 - (NSString *)km_weekdayName:(BOOL)isShortName localeIdentifier:(NSString *)localeIdentifier {
 69     NSDateFormatter *formatter = [NSDateFormatter new];
 70     formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
 71     formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:localeIdentifier];
 72     formatter.dateFormat = isShortName ? @"EE" : @"EEEE";
 73     return [formatter stringFromDate:self];
 74 }
 75 
 76 - (NSString *)km_weekdayNameCN:(BOOL)isShortName {
 77     /*
 78      // 方法一:
 79      NSArray *arrWeekdayName =
 80      isShortName
 81      ? @[ @"周日",
 82      @"周一",
 83      @"周二",
 84      @"周三",
 85      @"周四",
 86      @"周五",
 87      @"周六" ]
 88      : @[
 89      @"星期日",
 90      @"星期一",
 91      @"星期二",
 92      @"星期三",
 93      @"星期四",
 94      @"星期五",
 95      @"星期六"
 96      ];
 97      
 98      NSInteger weekday = [self weekday];
 99      return arrWeekdayName[weekday - 1];
100      */
101     
102     // 方法二:
103     return [self km_weekdayName:isShortName localeIdentifier:@"zh_CN"];
104 }
105 
106 - (NSString *)km_weekdayNameEN:(BOOL)isShortName {
107     return [self km_weekdayName:isShortName localeIdentifier:@"en_US"];
108 }
109 
110 @end

DateHelper.h

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface DateHelper : NSObject
 4 /**
 5  *  获取本地当前时间
 6  *
 7  *  @return 本地当前时间
 8  */
 9 + (NSDate *)localeDate;
10 
11 /**
12  *  根据时间字符串和其格式,获取对应的时间
13  *
14  *  @param dateStr 时间字符串
15  *  @param format  时间字符串格式(默认值为@"yyyy-MM-dd HH:mm")
16  *
17  *  @return 对应的时间
18  */
19 + (NSDate *)dateFromString:(NSString *)dateStr withFormat:(NSString *)format;
20 
21 /**
22  *  根据时间和其格式,获取对应的时间字符串
23  *
24  *  @param date    时间
25  *  @param format  时间字符串格式(默认值为@"yyyy-MM-dd HH:mm")
26  *
27  *  @return 对应的时间字符串
28  */
29 + (NSString *)dateToString:(NSDate *)date withFormat:(NSString *)format;
30 
31 @end 

DateHelper.m

 1 #import "DateHelper.h"
 2 
 3 @implementation DateHelper
 4 
 5 + (NSDate *)localeDate {
 6     NSDate *date = [NSDate date];
 7     NSTimeZone *zone = [NSTimeZone systemTimeZone];
 8     NSInteger interval = [zone secondsFromGMTForDate:date];
 9     return [date dateByAddingTimeInterval:interval];
10 }
11 
12 + (NSDate *)dateFromString:(NSString *)dateStr withFormat:(NSString *)format {
13     NSDateFormatter *formatter = [NSDateFormatter new];
14     formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
15     formatter.dateFormat = format ?: @"yyyy-MM-dd HH:mm";
16     return [formatter dateFromString:dateStr];
17 }
18 
19 + (NSString *)dateToString:(NSDate *)date withFormat:(NSString *)format {
20     NSDateFormatter *formatter = [NSDateFormatter new];
21     formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
22     formatter.dateFormat = format ?: @"yyyy-MM-dd HH:mm";
23     return [formatter stringFromDate:date];
24 }
25 
26 @end

KMDatePickerDateModel.h

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface KMDatePickerDateModel : NSObject
 4 @property (copy, nonatomic) NSString *year;
 5 @property (copy, nonatomic) NSString *month;
 6 @property (copy, nonatomic) NSString *day;
 7 @property (copy, nonatomic) NSString *hour;
 8 @property (copy, nonatomic) NSString *minute;
 9 @property (copy, nonatomic) NSString *weekdayName;
10 
11 - (instancetype)initWithDate:(NSDate *)date;
12 
13 @end 

KMDatePickerDateModel.m

 1 #import "KMDatePickerDateModel.h"
 2 #import "NSDate+CalculateDay.h"
 3 
 4 @implementation KMDatePickerDateModel
 5 
 6 - (instancetype)initWithDate:(NSDate *)date {
 7     if (self = [super init]) {
 8         NSDateFormatter *formatter = [NSDateFormatter new];
 9         formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
10         formatter.dateFormat = @"yyyyMMddHHmm";
11         NSString *dateStr = [formatter stringFromDate:date];
12         
13         _year = [dateStr substringWithRange:NSMakeRange(0, 4)];
14         _month = [dateStr substringWithRange:NSMakeRange(4, 2)];
15         _day = [dateStr substringWithRange:NSMakeRange(6, 2)];
16         _hour = [dateStr substringWithRange:NSMakeRange(8, 2)];
17         _minute = [dateStr substringWithRange:NSMakeRange(10, 2)];
18         _weekdayName = [date km_weekdayNameCN:YES];
19     }
20     return self;
21 }
22 
23 @end 

KMDatePicker.h

 1 #import <UIKit/UIKit.h>
 2 #import "KMDatePickerDateModel.h"
 3 
 4 typedef NS_ENUM(NSUInteger, KMDatePickerStyle) {
 5     KMDatePickerStyleYearMonthDayHourMinute,
 6     KMDatePickerStyleYearMonthDay,
 7     KMDatePickerStyleMonthDayHourMinute,
 8     KMDatePickerStyleHourMinute
 9 };
10 
11 @protocol KMDatePickerDelegate;
12 @interface KMDatePicker : UIView <UIPickerViewDataSource, UIPickerViewDelegate>
13 @property (nonatomic, weak) id<KMDatePickerDelegate> delegate;
14 @property (nonatomic, assign) KMDatePickerStyle datePickerStyle;
15 @property (nonatomic, strong) NSDate *minLimitedDate; ///< 最小限制时间;默认值为1970-01-01 00:00
16 @property (nonatomic, strong) NSDate *maxLimitedDate; ///< 最大限制时间;默认值为2060-12-31 23:59
17 @property (nonatomic, strong) NSDate *defaultLimitedDate; ///< 默认限制时间;默认值为最小限制时间,当选择时间不在指定范围,就滚动到此默认限制时间
18 @property (nonatomic, strong) NSDate *scrollToDate; ///< 滚动到指定时间;默认值为当前时间
19 
20 - (instancetype)initWithFrame:(CGRect)frame delegate:(id<KMDatePickerDelegate>)delegate datePickerStyle:(KMDatePickerStyle)datePickerStyle;
21 
22 @end
23 
24 @protocol KMDatePickerDelegate <NSObject>
25 @required
26 - (void)datePicker:(KMDatePicker *)datePicker didSelectDate:(KMDatePickerDateModel *)datePickerDate;
27 
28 @end

KMDatePicker.m

  1 #import "KMDatePicker.h"
  2 #import "NSDate+CalculateDay.h"
  3 #import "DateHelper.h"
  4 
  5 #define kDefaultMinLimitedDate @"1970-01-01 00:00"
  6 #define kDefaultMaxLimitedDate @"2060-12-31 23:59"
  7 #define kMonthCountOfEveryYear 12
  8 #define kHourCountOfEveryDay 24
  9 #define kMinuteCountOfEveryHour 60
 10 #define kRowDisabledStatusColor [UIColor redColor]
 11 #define kRowNormalStatusColor [UIColor blackColor]
 12 #define kWidthOfTotal self.frame.size.width
 13 #define kHeightOfButtonContentView 35.0
 14 #define kButtonNormalStatusColor [UIColor colorWithRed:0.0 green:0.5 blue:1.0 alpha:1.0]
 15 
 16 @interface KMDatePicker () {
 17     UIPickerView *_pikV;
 18     
 19     // 最小和最大限制时间、滚动到指定时间实体对象实例
 20     KMDatePickerDateModel *_datePickerDateMinLimited;
 21     KMDatePickerDateModel *_datePickerDateMaxLimited;
 22     KMDatePickerDateModel *_datePickerDateScrollTo;
 23     
 24     // 存储时间数据源的数组
 25     NSMutableArray *_mArrYear;
 26     NSMutableArray *_mArrMonth;
 27     NSMutableArray *_mArrDay;
 28     NSMutableArray *_mArrHour;
 29     NSMutableArray *_mArrMinute;
 30     
 31     // 时间数据源的数组中,选中元素的索引
 32     NSInteger _yearIndex;
 33     NSInteger _monthIndex;
 34     NSInteger _dayIndex;
 35     NSInteger _hourIndex;
 36     NSInteger _minuteIndex;
 37 }
 38 
 39 @end
 40 
 41 @implementation KMDatePicker
 42 
 43 - (instancetype)init {
 44     if (self = [super init]) {
 45         self.backgroundColor = [UIColor whiteColor];
 46     }
 47     return self;
 48 }
 49 
 50 - (instancetype)initWithFrame:(CGRect)frame {
 51     if (self = [super initWithFrame:frame]) {
 52         self.backgroundColor = [UIColor whiteColor];
 53     }
 54     return self;
 55 }
 56 
 57 - (instancetype)initWithFrame:(CGRect)frame delegate:(id<KMDatePickerDelegate>)delegate datePickerStyle:(KMDatePickerStyle)datePickerStyle {
 58     _delegate = delegate;
 59     _datePickerStyle = datePickerStyle;
 60     return [self initWithFrame:frame];
 61 }
 62 
 63 #pragma mark - 重写属性
 64 - (void)setMinLimitedDate:(NSDate *)minLimitedDate {
 65     _minLimitedDate = minLimitedDate;
 66     if (_minLimitedDate && !_defaultLimitedDate) {
 67         _defaultLimitedDate = _minLimitedDate;
 68     }
 69 }
 70 
 71 #pragma mark - 自定义方法
 72 - (void)addUnitLabel:(NSString *)text withPointX:(CGFloat)pointX {
 73     CGFloat pointY = _pikV.frame.size.height/2 - 10.0 + kHeightOfButtonContentView;
 74     UILabel *lblUnit = [[UILabel alloc] initWithFrame:CGRectMake(pointX, pointY, 20.0, 20.0)];
 75     lblUnit.text = text;
 76     lblUnit.textAlignment = NSTextAlignmentCenter;
 77     lblUnit.textColor = [UIColor blackColor];
 78     lblUnit.backgroundColor = [UIColor clearColor];
 79     lblUnit.font = [UIFont systemFontOfSize:18.0];
 80     lblUnit.layer.shadowColor = [[UIColor whiteColor] CGColor];
 81     lblUnit.layer.shadowOpacity = 0.5;
 82     lblUnit.layer.shadowRadius = 5.0;
 83     [self addSubview:lblUnit];
 84 }
 85 
 86 - (NSUInteger)daysOfMonth {
 87     NSString *dateStr = [NSString stringWithFormat:@"%@-%@-01 00:00", _mArrYear[_yearIndex], _mArrMonth[_monthIndex]];
 88     return [[DateHelper dateFromString:dateStr withFormat:@"yyyy-MM-dd HH:mm"] km_daysOfMonth];
 89 }
 90 
 91 - (void)reloadDayArray {
 92     _mArrDay = [NSMutableArray new];
 93     for (NSUInteger i=1, len=[self daysOfMonth]; i<=len; i++) {
 94         [_mArrDay addObject:[NSString stringWithFormat:@"%02ld", (long)i]];
 95     }
 96 }
 97 
 98 - (void)loadData {
 99     // 初始化最小和最大限制时间、滚动到指定时间实体对象实例
100     if (!_minLimitedDate) {
101         _minLimitedDate = [DateHelper dateFromString:kDefaultMinLimitedDate withFormat:nil];
102     }
103     _datePickerDateMinLimited = [[KMDatePickerDateModel alloc] initWithDate:_minLimitedDate];
104     
105     if (!_maxLimitedDate) {
106         _maxLimitedDate = [DateHelper dateFromString:kDefaultMaxLimitedDate withFormat:nil];
107     }
108     _datePickerDateMaxLimited = [[KMDatePickerDateModel alloc] initWithDate:_maxLimitedDate];
109     
110     // 滚动到指定时间;默认值为当前时间。如果是使用自定义时间小于最小限制时间,这时就以最小限制时间为准;如果是使用自定义时间大于最大限制时间,这时就以最大限制时间为准
111     if (!_scrollToDate) {
112         _scrollToDate = [DateHelper localeDate];
113     }
114     if ([_scrollToDate compare:_minLimitedDate] == NSOrderedAscending) {
115         _scrollToDate = _minLimitedDate;
116     } else if ([_scrollToDate compare:_maxLimitedDate] == NSOrderedDescending) {
117         _scrollToDate = _maxLimitedDate;
118     }
119     _datePickerDateScrollTo = [[KMDatePickerDateModel alloc] initWithDate:_scrollToDate];
120     
121     // 初始化存储时间数据源的数组
122     //
123     _mArrYear = [NSMutableArray new];
124     for (NSInteger beginVal=[_datePickerDateMinLimited.year integerValue], endVal=[_datePickerDateMaxLimited.year integerValue]; beginVal<=endVal; beginVal++) {
125         [_mArrYear addObject:[NSString stringWithFormat:@"%ld", (long)beginVal]];
126     }
127     _yearIndex = [_datePickerDateScrollTo.year integerValue] - [_datePickerDateMinLimited.year integerValue];
128     
129     //
130     _mArrMonth = [[NSMutableArray alloc] initWithCapacity:kMonthCountOfEveryYear];
131     for (NSInteger i=1; i<=kMonthCountOfEveryYear; i++) {
132         [_mArrMonth addObject:[NSString stringWithFormat:@"%02ld", (long)i]];
133     }
134     _monthIndex = [_datePickerDateScrollTo.month integerValue] - 1;
135     
136     //
137     [self reloadDayArray];
138     _dayIndex = [_datePickerDateScrollTo.day integerValue] - 1;
139     
140     //
141     _mArrHour = [[NSMutableArray alloc] initWithCapacity:kHourCountOfEveryDay];
142     for (NSInteger i=0; i<kHourCountOfEveryDay; i++) {
143         [_mArrHour addObject:[NSString stringWithFormat:@"%02ld", (long)i]];
144     }
145     _hourIndex = [_datePickerDateScrollTo.hour integerValue];
146     
147     //
148     _mArrMinute = [[NSMutableArray alloc] initWithCapacity:kMinuteCountOfEveryHour];
149     for (NSInteger i=0; i<kMinuteCountOfEveryHour; i++) {
150         [_mArrMinute addObject:[NSString stringWithFormat:@"%02ld", (long)i]];
151     }
152     _minuteIndex = [_datePickerDateScrollTo.minute integerValue];
153 }
154 
155 - (void)scrollToDateIndexPosition {
156     NSArray *arrIndex;
157     switch (_datePickerStyle) {
158         case KMDatePickerStyleYearMonthDayHourMinute: {
159             arrIndex = @[
160                          [NSNumber numberWithInteger:_yearIndex],
161                          [NSNumber numberWithInteger:_monthIndex],
162                          [NSNumber numberWithInteger:_dayIndex],
163                          [NSNumber numberWithInteger:_hourIndex],
164                          [NSNumber numberWithInteger:_minuteIndex]
165                          ];
166             break;
167         }
168         case KMDatePickerStyleYearMonthDay: {
169             arrIndex = @[
170                          [NSNumber numberWithInteger:_yearIndex],
171                          [NSNumber numberWithInteger:_monthIndex],
172                          [NSNumber numberWithInteger:_dayIndex]
173                          ];
174             break;
175         }
176         case KMDatePickerStyleMonthDayHourMinute: {
177             arrIndex = @[
178                          [NSNumber numberWithInteger:_monthIndex],
179                          [NSNumber numberWithInteger:_dayIndex],
180                          [NSNumber numberWithInteger:_hourIndex],
181                          [NSNumber numberWithInteger:_minuteIndex]
182                          ];
183             break;
184         }
185         case KMDatePickerStyleHourMinute: {
186             arrIndex = @[
187                          [NSNumber numberWithInteger:_hourIndex],
188                          [NSNumber numberWithInteger:_minuteIndex]
189                          ];
190             break;
191         }
192     }
193 
194     for (NSUInteger i=0, len=arrIndex.count; i<len; i++) {
195         [_pikV selectRow:[arrIndex[i] integerValue] inComponent:i animated:YES];
196     }
197 }
198 
199 - (BOOL)validatedDate:(NSDate *)date {
200     NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@",
201                             _datePickerDateMinLimited.year,
202                             _datePickerDateMinLimited.month,
203                             _datePickerDateMinLimited.day,
204                             _datePickerDateMinLimited.hour,
205                             _datePickerDateMinLimited.minute
206                             ];
207     
208     return !([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending ||
209              [date compare:_maxLimitedDate] == NSOrderedDescending);
210 }
211 
212 - (BOOL)canShowScrollToNowButton {
213     return [self validatedDate:[DateHelper localeDate]];
214 }
215 
216 - (void)cancel:(UIButton *)sender {
217     UIViewController *delegateVC = (UIViewController *)self.delegate;
218     [delegateVC.view endEditing:YES];
219 }
220 
221 - (void)scrollToNowDateIndexPosition:(UIButton *)sender {
222     [self scrollToDateIndexPositionWithDate:[DateHelper localeDate]];
223 }
224 
225 - (void)scrollToDateIndexPositionWithDate:(NSDate *)date {
226     // 为了区别最大最小限制范围外行的标签颜色,这里需要重新加载所有组件列
227     [_pikV reloadAllComponents];
228     
229     _scrollToDate = date;
230     _datePickerDateScrollTo = [[KMDatePickerDateModel alloc] initWithDate:_scrollToDate];
231     _yearIndex = [_datePickerDateScrollTo.year integerValue] - [_datePickerDateMinLimited.year integerValue];
232     _monthIndex = [_datePickerDateScrollTo.month integerValue] - 1;
233     _dayIndex = [_datePickerDateScrollTo.day integerValue] - 1;
234     _hourIndex = [_datePickerDateScrollTo.hour integerValue];
235     _minuteIndex = [_datePickerDateScrollTo.minute integerValue];
236     [self scrollToDateIndexPosition];
237 }
238 
239 - (void)confirm:(UIButton *)sender {
240     [self playDelegateAfterSelectedRow];
241     
242     [self cancel:sender];
243 }
244 
245 - (UIColor *)monthRowTextColor:(NSInteger)row {
246     UIColor *color = kRowNormalStatusColor;
247     NSString *dateStr = [NSString stringWithFormat:@"%@-%@-01 00:00",
248                          _mArrYear[_yearIndex],
249                          _mArrMonth[row]
250                          ];
251     NSDate *date = [DateHelper dateFromString:dateStr withFormat:nil];
252     
253     NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-01 00:00",
254                          _datePickerDateMinLimited.year,
255                          _datePickerDateMinLimited.month
256                          ];
257     
258     if ([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending ||
259         [date compare:_maxLimitedDate] == NSOrderedDescending) {
260         color = kRowDisabledStatusColor;
261     }
262     
263     return color;
264 }
265 
266 - (UIColor *)dayRowTextColor:(NSInteger)row {
267     UIColor *color = kRowNormalStatusColor;
268     NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ 00:00",
269                          _mArrYear[_yearIndex],
270                          _mArrMonth[_monthIndex],
271                          _mArrDay[row]
272                          ];
273     NSDate *date = [DateHelper dateFromString:dateStr withFormat:nil];
274     
275     NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ 00:00",
276                             _datePickerDateMinLimited.year,
277                             _datePickerDateMinLimited.month,
278                             _datePickerDateMinLimited.day
279                             ];
280     
281     if ([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending ||
282         [date compare:_maxLimitedDate] == NSOrderedDescending) {
283         color = kRowDisabledStatusColor;
284     }
285     
286     return color;
287 }
288 
289 - (UIColor *)hourRowTextColor:(NSInteger)row {
290     UIColor *color = kRowNormalStatusColor;
291     NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:00",
292                          _mArrYear[_yearIndex],
293                          _mArrMonth[_monthIndex],
294                          _mArrDay[_dayIndex],
295                          _mArrHour[row]
296                          ];
297     NSDate *date = [DateHelper dateFromString:dateStr withFormat:nil];
298     
299     NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:00",
300                             _datePickerDateMinLimited.year,
301                             _datePickerDateMinLimited.month,
302                             _datePickerDateMinLimited.day,
303                             _datePickerDateMinLimited.hour
304                             ];
305     
306     if ([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending ||
307         [date compare:_maxLimitedDate] == NSOrderedDescending) {
308         color = kRowDisabledStatusColor;
309     }
310     
311     return color;
312 }
313 
314 - (UIColor *)minuteRowTextColor:(NSInteger)row {
315     NSString *format = @"yyyy-MM-dd HH:mm:ss";
316     UIColor *color = kRowNormalStatusColor;
317     NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@:00",
318                          _mArrYear[_yearIndex],
319                          _mArrMonth[_monthIndex],
320                          _mArrDay[_dayIndex],
321                          _mArrHour[_hourIndex],
322                          _mArrMinute[row]
323                          ];
324     NSDate *date = [DateHelper dateFromString:dateStr withFormat:format];
325     
326     NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@:00",
327                             _datePickerDateMinLimited.year,
328                             _datePickerDateMinLimited.month,
329                             _datePickerDateMinLimited.day,
330                             _datePickerDateMinLimited.hour,
331                             _datePickerDateMinLimited.minute
332                             ];
333     
334     if ([date compare:[DateHelper dateFromString:minDateStr withFormat:format]] == NSOrderedAscending ||
335         [date compare:_maxLimitedDate] == NSOrderedDescending) {
336         color = kRowDisabledStatusColor;
337     }
338     
339     return color;
340 }
341 
342 #pragma mark - 绘制内容
343 - (void)drawRect:(CGRect)rect {
344     // 加载数据
345     [self loadData];
346     
347     // 初始化头部按钮(取消、现在时间、确定)
348     UIView *buttonContentView = [[UIView alloc] initWithFrame:CGRectMake(-2.0, 0.0, kWidthOfTotal + 4.0, kHeightOfButtonContentView)];
349     buttonContentView.layer.borderColor = [UIColor lightGrayColor].CGColor;
350     buttonContentView.layer.borderWidth = 0.5;
351     [self addSubview:buttonContentView];
352     
353     UIButton *btnCancel = [UIButton buttonWithType:UIButtonTypeCustom];
354     btnCancel.frame = CGRectMake(2.0, 2.5, 60.0, kHeightOfButtonContentView - 5.0);
355     btnCancel.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
356     [btnCancel setTitle:@"取消" forState:UIControlStateNormal];
357     [btnCancel setTitleColor:kButtonNormalStatusColor forState:UIControlStateNormal];
358     [btnCancel addTarget:self
359                   action:@selector(cancel:)
360         forControlEvents:UIControlEventTouchUpInside];
361     [buttonContentView addSubview:btnCancel];
362     
363     if ([self canShowScrollToNowButton]) {
364         UIButton *btnScrollToNow = [UIButton buttonWithType:UIButtonTypeCustom];
365         btnScrollToNow.frame = CGRectMake(buttonContentView.frame.size.width/2 - 50.0, 2.5, 100.0, kHeightOfButtonContentView - 5.0);
366         btnScrollToNow.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
367         [btnScrollToNow setTitle:@"现在时间" forState:UIControlStateNormal];
368         [btnScrollToNow setTitleColor:kButtonNormalStatusColor forState:UIControlStateNormal];
369         [btnScrollToNow addTarget:self
370                            action:@selector(scrollToNowDateIndexPosition:)
371                  forControlEvents:UIControlEventTouchUpInside];
372         [buttonContentView addSubview:btnScrollToNow];
373     }
374     
375     UIButton *btnConfirm = [UIButton buttonWithType:UIButtonTypeCustom];
376     btnConfirm.frame = CGRectMake(kWidthOfTotal - 58.0, 2.5, 60.0, kHeightOfButtonContentView - 5.0);
377     btnConfirm.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
378     [btnConfirm setTitle:@"确定" forState:UIControlStateNormal];
379     [btnConfirm setTitleColor:kButtonNormalStatusColor forState:UIControlStateNormal];
380     [btnConfirm addTarget:self
381                    action:@selector(confirm:)
382          forControlEvents:UIControlEventTouchUpInside];
383     [buttonContentView addSubview:btnConfirm];
384     
385     // 初始化选择器视图控件
386     if (!_pikV) {
387         _pikV = [[UIPickerView alloc]initWithFrame:CGRectMake(0.0, kHeightOfButtonContentView, kWidthOfTotal, self.frame.size.height - kHeightOfButtonContentView)];
388         _pikV.showsSelectionIndicator = YES;
389         _pikV.backgroundColor = [UIColor clearColor];
390         [self addSubview:_pikV];
391     }
392     _pikV.dataSource = self;
393     _pikV.delegate = self;
394     
395     // 初始化滚动到指定时间位置
396     [self scrollToDateIndexPosition];
397 }
398 
399 #pragma mark - 执行 KMDatePickerDelegate 委托代理协议方法,用于回调传递参数
400 - (void)playDelegateAfterSelectedRow {
401     if ([self.delegate respondsToSelector:@selector(datePicker:didSelectDate:)]) {
402         [self.delegate datePicker:self
403                     didSelectDate:_datePickerDateScrollTo];
404     }
405 }
406 
407 #pragma mark - UIPickerViewDataSource
408 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
409     NSInteger numberOfComponents = 0;
410     switch (_datePickerStyle) {
411         case KMDatePickerStyleYearMonthDayHourMinute: {
412             numberOfComponents = 5;
413             break;
414         }
415         case KMDatePickerStyleYearMonthDay: {
416             numberOfComponents = 3;
417             break;
418         }
419         case KMDatePickerStyleMonthDayHourMinute: {
420             numberOfComponents = 4;
421             break;
422         }
423         case KMDatePickerStyleHourMinute: {
424             numberOfComponents = 2;
425             break;
426         }
427     }
428     return numberOfComponents;
429 }
430 
431 - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
432     NSInteger numberOfRows = 0;
433     switch (_datePickerStyle) {
434         case KMDatePickerStyleYearMonthDayHourMinute: {
435             switch (component) {
436                 case 0:
437                     numberOfRows = _mArrYear.count;
438                     break;
439                 case 1:
440                     numberOfRows = kMonthCountOfEveryYear;
441                     break;
442                 case 2:
443                     numberOfRows = [self daysOfMonth];
444                     break;
445                 case 3:
446                     numberOfRows = kHourCountOfEveryDay;
447                     break;
448                 case 4:
449                     numberOfRows = kMinuteCountOfEveryHour;
450                     break;
451             }
452             break;
453         }
454         case KMDatePickerStyleYearMonthDay: {
455             switch (component) {
456                 case 0:
457                     numberOfRows = _mArrYear.count;
458                     break;
459                 case 1:
460                     numberOfRows = kMonthCountOfEveryYear;
461                     break;
462                 case 2:
463                     numberOfRows = [self daysOfMonth];
464                     break;
465             }
466             break;
467         }
468         case KMDatePickerStyleMonthDayHourMinute: {
469             switch (component) {
470                 case 0:
471                     numberOfRows = kMonthCountOfEveryYear;
472                     break;
473                 case 1:
474                     numberOfRows = [self daysOfMonth];
475                     break;
476                 case 2:
477                     numberOfRows = kHourCountOfEveryDay;
478                     break;
479                 case 3:
480                     numberOfRows = kMinuteCountOfEveryHour;
481                     break;
482             }
483             break;
484         }
485         case KMDatePickerStyleHourMinute: {
486             switch (component) {
487                 case 0:
488                     numberOfRows = kHourCountOfEveryDay;
489                     break;
490                 case 1:
491                     numberOfRows = kMinuteCountOfEveryHour;
492                     break;
493             }
494             break;
495         }
496     }
497     return numberOfRows;
498 }
499 
500 #pragma mark - UIPickerViewDelegate
501 - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
502     CGFloat width = 50.0;
503     CGFloat widthOfAverage;
504     
505     switch (_datePickerStyle) {
506         case KMDatePickerStyleYearMonthDayHourMinute: {
507             // 规则一:平均宽度 = (总共宽度 - 年份相比多两个数字的宽度 - 分钟会是右对齐导致需偏移宽度来显示「分」这个文字) / 5等份
508             widthOfAverage = (kWidthOfTotal - 20.0 - 25.0) / 5;
509             switch (component) {
510                 case 0:
511                     width = widthOfAverage + 20.0;
512                     // 规则二:单位标签的 X 坐标位置 = 列的水平居中 X 坐标 + 偏移量
513                     [self addUnitLabel:@"" withPointX:width/2 + 24.0];
514                     break;
515                 case 1:
516                     width = widthOfAverage;
517                     [self addUnitLabel:@"" withPointX:(widthOfAverage + 20.0) + width/2 + 16.0];
518                     break;
519                 case 2:
520                     width = widthOfAverage;
521                     [self addUnitLabel:@"" withPointX:(2*widthOfAverage + 20.0) + width/2 + 22.0];
522                     break;
523                 case 3:
524                     width = widthOfAverage;
525                     [self addUnitLabel:@"" withPointX:(3*widthOfAverage + 20.0) + width/2 + 28.0];
526                     break;
527                 case 4:
528                     width = widthOfAverage;
529                     [self addUnitLabel:@"" withPointX:(4*widthOfAverage + 20.0) + width/2 + 32.0];
530                     break;
531             }
532             break;
533         }
534         case KMDatePickerStyleYearMonthDay: {
535             widthOfAverage = (kWidthOfTotal - 20.0 - 15.0) / 3;
536             switch (component) {
537                 case 0:
538                     width = widthOfAverage + 20.0;
539                     [self addUnitLabel:@"" withPointX:width/2 + 24.0];
540                     break;
541                 case 1:
542                     width = widthOfAverage;
543                     [self addUnitLabel:@"" withPointX:(widthOfAverage + 20.0) + width/2 + 16.0];
544                     break;
545                 case 2:
546                     width = widthOfAverage;
547                     [self addUnitLabel:@"" withPointX:(2*widthOfAverage + 20.0) + width/2 + 22.0];
548                     break;
549             }
550             break;
551         }
552         case KMDatePickerStyleMonthDayHourMinute: {
553             widthOfAverage = (kWidthOfTotal - 20.0) / 4;
554             switch (component) {
555                 case 0:
556                     width = widthOfAverage;
557                     [self addUnitLabel:@"" withPointX:width/2 + 11.0];
558                     break;
559                 case 1:
560                     width = widthOfAverage;
561                     [self addUnitLabel:@"" withPointX:widthOfAverage + width/2 + 17.0];
562                     break;
563                 case 2:
564                     width = widthOfAverage;
565                     [self addUnitLabel:@"" withPointX:2*widthOfAverage + width/2 + 23.0];
566                     break;
567                 case 3:
568                     width = widthOfAverage;
569                     [self addUnitLabel:@"" withPointX:3*widthOfAverage + width/2 + 27.0];
570                     break;
571             }
572             break;
573         }
574         case KMDatePickerStyleHourMinute: {
575             widthOfAverage = (kWidthOfTotal - 10.0) / 2;
576             switch (component) {
577                 case 0:
578                     width = widthOfAverage;
579                     [self addUnitLabel:@"" withPointX:width/2 + 12.0];
580                     break;
581                 case 1:
582                     width = widthOfAverage;
583                     [self addUnitLabel:@"" withPointX:widthOfAverage + width/2 + 18.0];
584                     break;
585             }
586             break;
587         }
588     }
589     return width;
590 }
591 
592 - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component {
593     return 30.0;
594 }
595 
596 - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view {
597     UILabel *lblCustom = (UILabel *)view;
598     if (!lblCustom) {
599         lblCustom = [UILabel new];
600         lblCustom.textAlignment = NSTextAlignmentCenter;
601         lblCustom.font = [UIFont systemFontOfSize:18.0];
602     }
603     
604     NSString *text;
605     UIColor *textColor = kRowNormalStatusColor;
606     switch (_datePickerStyle) {
607         case KMDatePickerStyleYearMonthDayHourMinute: {
608             switch (component) {
609                 case 0:
610                     text = _mArrYear[row];
611                     break;
612                 case 1:
613                     text = _mArrMonth[row];
614                     textColor = [self monthRowTextColor:row];
615                     break;
616                 case 2:
617                     text = _mArrDay[row];
618                     textColor = [self dayRowTextColor:row];
619                     break;
620                 case 3:
621                     text = _mArrHour[row];
622                     textColor = [self hourRowTextColor:row];
623                     break;
624                 case 4:
625                     text = _mArrMinute[row];
626                     textColor = [self minuteRowTextColor:row];
627                     break;
628             }
629             break;
630         }
631         case KMDatePickerStyleYearMonthDay: {
632             switch (component) {
633                 case 0:
634                     text = _mArrYear[row];
635                     break;
636                 case 1:
637                     text = _mArrMonth[row];
638                     textColor = [self monthRowTextColor:row];
639                     break;
640                 case 2:
641                     text = _mArrDay[row];
642                     textColor = [self dayRowTextColor:row];
643                     break;
644             }
645             break;
646         }
647         case KMDatePickerStyleMonthDayHourMinute: {
648             switch (component) {
649                 case 0:
650                     text = _mArrMonth[row];
651                     textColor = [self monthRowTextColor:row];
652                     break;
653                 case 1:
654                     text = _mArrDay[row];
655                     textColor = [self dayRowTextColor:row];
656                     break;
657                 case 2:
658                     text = _mArrHour[row];
659                     textColor = [self hourRowTextColor:row];
660                     break;
661                 case 3:
662                     text = _mArrMinute[row];
663                     textColor = [self minuteRowTextColor:row];
664                     break;
665             }
666             break;
667         }
668         case KMDatePickerStyleHourMinute: {
669             switch (component) {
670                 case 0:
671                     text = _mArrHour[row];
672                     textColor = [self hourRowTextColor:row];
673                     break;
674                 case 1:
675                     text = _mArrMinute[row];
676                     textColor = [self minuteRowTextColor:row];
677                     break;
678             }
679             break;
680         }
681     }
682     lblCustom.text = text;
683     lblCustom.textColor = textColor;
684     return lblCustom;
685 }
686 
687 - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
688     switch (_datePickerStyle) {
689         case KMDatePickerStyleYearMonthDayHourMinute: {
690             switch (component) {
691                 case 0:
692                     _yearIndex = row;
693                     break;
694                 case 1:
695                     _monthIndex = row;
696                     break;
697                 case 2:
698                     _dayIndex = row;
699                     break;
700                 case 3:
701                     _hourIndex = row;
702                     break;
703                 case 4:
704                     _minuteIndex = row;
705                     break;
706             }
707             if (component == 0 || component == 1) {
708                 [self reloadDayArray];
709                 if (_mArrDay.count-1 < _dayIndex) {
710                     _dayIndex = _mArrDay.count-1;
711                 }
712             }
713             break;
714         }
715         case KMDatePickerStyleYearMonthDay: {
716             switch (component) {
717                 case 0:
718                     _yearIndex = row;
719                     break;
720                 case 1:
721                     _monthIndex = row;
722                     break;
723                 case 2:
724                     _dayIndex = row;
725                     break;
726             }
727             if (component == 0 || component == 1) {
728                 [self reloadDayArray];
729                 if (_mArrDay.count-1 < _dayIndex) {
730                     _dayIndex = _mArrDay.count-1;
731                 }
732             }
733             break;
734         }
735         case KMDatePickerStyleMonthDayHourMinute: {
736             switch (component) {
737                 case 0:
738                     _monthIndex = row;
739                     break;
740                 case 1:
741                     _dayIndex = row;
742                     break;
743                 case 2:
744                     _hourIndex = row;
745                     break;
746                 case 3:
747                     _minuteIndex = row;
748                     break;
749             }
750             if (component == 0) {
751                 [self reloadDayArray];
752                 if (_mArrDay.count-1 < _dayIndex) {
753                     _dayIndex = _mArrDay.count-1;
754                 }
755             }
756             break;
757         }
758         case KMDatePickerStyleHourMinute: {
759             switch (component) {
760                 case 0:
761                     _hourIndex = row;
762                     break;
763                 case 1:
764                     _minuteIndex = row;
765                     break;
766             }
767             break;
768         }
769     }
770     
771     NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@",
772                          _mArrYear[_yearIndex],
773                          _mArrMonth[_monthIndex],
774                          _mArrDay[_dayIndex],
775                          _mArrHour[_hourIndex],
776                          _mArrMinute[_minuteIndex]
777                          ];
778     _scrollToDate = [DateHelper dateFromString:dateStr withFormat:nil];
779     _datePickerDateScrollTo = [[KMDatePickerDateModel alloc] initWithDate:_scrollToDate];
780     
781     // 为了区别最大最小限制范围外行的标签颜色,这里需要重新加载所有组件列
782     [pickerView reloadAllComponents];
783     
784     // 如果选择时间不在最小和最大限制时间范围内就滚动到有效的默认范围内
785     if (![self validatedDate:_scrollToDate]) {
786         [self scrollToDateIndexPositionWithDate:_defaultLimitedDate];
787     }
788 }
789 
790 @end

 

源码下载地址:

https://github.com/KenmuHuang/KMDatePicker

 

2016-04-06,已更新 GitHub 内容:添加默认限制时间属性;默认值为最小限制时间,当选择时间不在指定范围,就滚动到此默认限制时间;解决跨月份无法处理好限制的问题

 

posted @ 2015-10-13 13:39  KenmuHuang  阅读(3321)  评论(6编辑  收藏  举报
如果您看完本篇博文,觉得对您有所收获,请点击右下角的 [推荐]
如果您想转载,请注明出处(原创内容,请尊重个人劳动成果)
如果您有任何意见或建议,欢迎留言
感谢您的阅读,敬请关注我的后续博客文章