·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> app软件开发 >> IOS开发 >> 自定义支持多种格式可控范围的时间选择器控件

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

作者:佚名      IOS开发编辑:admin      更新时间:2022-07-23

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

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

NSDate+CalculateDay.m

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

 

源码下载地址:

https://github.com/KenmuHuang/KMDatePicker