你的位置:首页 > 操作系统

[操作系统]自定义支持多种格式可控范围的时间选择器控件


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

(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 ViewController10 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:rect28                 delegate:self29                 datePickerStyle:KMDatePickerStyleYearMonthDayHourMinute];30   _txtFYearMonthDayHourMinute.inputView = datePicker;31   _txtFYearMonthDayHourMinute.delegate = self;32   33   //年月日34   datePicker = [[KMDatePicker alloc]35          initWithFrame:rect36          delegate:self37          datePickerStyle:KMDatePickerStyleYearMonthDay];38   _txtFYearMonthDay.inputView = datePicker;39   _txtFYearMonthDay.delegate = self;40   41   //月日时分42   datePicker = [[KMDatePicker alloc]43          initWithFrame:rect44          delegate:self45          datePickerStyle:KMDatePickerStyleMonthDayHourMinute];46   _txtFMonthDayHourMinute.inputView = datePicker;47   _txtFMonthDayHourMinute.delegate = self;48   49   //时分50   datePicker = [[KMDatePicker alloc]51          initWithFrame:rect52          delegate:self53          datePickerStyle:KMDatePickerStyleHourMinute];54   _txtFHourMinute.inputView = datePicker;55   _txtFHourMinute.delegate = self;56   57   //年月日时分;限制时间范围58   datePicker = [[KMDatePicker alloc]59          initWithFrame:rect60          delegate:self61          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 - UITextFieldDelegate73 - (void)textFieldDidBeginEditing:(UITextField *)textField {74   _txtFCurrent = textField;75 }76 77 #pragma mark - KMDatePickerDelegate78 - (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.weekdayName86              ];87   _txtFCurrent.text = dateStr;88 }89 90 @end 

Main.storyboard

 1 <??> 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:0016 @property (strong, nonatomic) NSDate *maxLimitedDate; //最大限制时间;默认值为2060-12-31 23:5917 @property (strong, nonatomic) NSDate *scrollToDate; //滚动到指定时间;默认值为当前时间18 19 - (instancetype)initWithFrame:(CGRect)frame delegate:(id<KMDatePickerDelegate>)delegate datePickerStyle:(KMDatePickerStyle)datePickerStyle;20 21 @end22 23 @protocol KMDatePickerDelegate <NSObject>24 @required25 - (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.minute214               ];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.month260              ];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.day283               ];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.hour308               ];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.minute336               ];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:self363          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:self374               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:self385           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:self407           didSelectDate:datePickerDateScrollTo];408   }409 }410 411 #pragma mark - UIPickerViewDataSource412 - (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 - UIPickerViewDelegate505 - (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