自定义支持多种格式可控范围的时间选择器控件
支持四种格式,可控制可选时间范围,如下:
(1)年月日时分
(2)年月日
(3)月日时分
(4)时分
效果如下:
iPhone 5s
iPhone 6
iPhone 6 Plus
ViewController.h
1 #import <UIKit/UIKit.h> 2 #import "KMDatePicker.h" 3 4 @interface ViewController : UIViewController <UITextFieldDelegate, KMDatePickerDelegate> 5 @property (strong, nonatomic) UITextField *txtFCurrent; 6 7 @property (strong, nonatomic) IBOutlet UITextField *txtFYearMonthDayHourMinute; 8 @property (strong, nonatomic) IBOutlet UITextField *txtFMonthDayHourMinute; 9 @property (strong, nonatomic) IBOutlet UITextField *txtFYearMonthDay; 10 @property (strong, nonatomic) IBOutlet UITextField *txtFHourMinute; 11 @property (strong, nonatomic) IBOutlet UITextField *txtFLimitedDate; 12 13 @end
ViewController.m
1 #import "ViewController.h" 2 #import "DateHelper.h" 3 #import "NSDate+CalculateDay.h" 4 5 @interface ViewController () 6 - (void)layoutUI; 7 @end 8 9 @implementation ViewController 10 11 - (void)viewDidLoad { 12 [super viewDidLoad]; 13 14 [self layoutUI]; 15 } 16 17 - (void)didReceiveMemoryWarning { 18 [super didReceiveMemoryWarning]; 19 // Dispose of any resources that can be recreated. 20 } 21 22 - (void)layoutUI { 23 CGRect rect = [[UIScreen mainScreen] bounds]; 24 rect = CGRectMake(0.0, 0.0, rect.size.width, 216.0); 25 //年月日时分 26 KMDatePicker *datePicker = [[KMDatePicker alloc] 27 initWithFrame:rect 28 delegate:self 29 datePickerStyle:KMDatePickerStyleYearMonthDayHourMinute]; 30 _txtFYearMonthDayHourMinute.inputView = datePicker; 31 _txtFYearMonthDayHourMinute.delegate = self; 32 33 //年月日 34 datePicker = [[KMDatePicker alloc] 35 initWithFrame:rect 36 delegate:self 37 datePickerStyle:KMDatePickerStyleYearMonthDay]; 38 _txtFYearMonthDay.inputView = datePicker; 39 _txtFYearMonthDay.delegate = self; 40 41 //月日时分 42 datePicker = [[KMDatePicker alloc] 43 initWithFrame:rect 44 delegate:self 45 datePickerStyle:KMDatePickerStyleMonthDayHourMinute]; 46 _txtFMonthDayHourMinute.inputView = datePicker; 47 _txtFMonthDayHourMinute.delegate = self; 48 49 //时分 50 datePicker = [[KMDatePicker alloc] 51 initWithFrame:rect 52 delegate:self 53 datePickerStyle:KMDatePickerStyleHourMinute]; 54 _txtFHourMinute.inputView = datePicker; 55 _txtFHourMinute.delegate = self; 56 57 //年月日时分;限制时间范围 58 datePicker = [[KMDatePicker alloc] 59 initWithFrame:rect 60 delegate:self 61 datePickerStyle:KMDatePickerStyleYearMonthDayHourMinute]; 62 datePicker.minLimitedDate = [[DateHelper localeDate] km_addMonthAndDay:-24 days:0]; 63 datePicker.maxLimitedDate = [datePicker.minLimitedDate km_addMonthAndDay:48 days:0]; 64 _txtFLimitedDate.inputView = datePicker; 65 _txtFLimitedDate.delegate = self; 66 } 67 68 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 69 [self.view endEditing:YES]; 70 } 71 72 #pragma mark - UITextFieldDelegate 73 - (void)textFieldDidBeginEditing:(UITextField *)textField { 74 _txtFCurrent = textField; 75 } 76 77 #pragma mark - KMDatePickerDelegate 78 - (void)datePicker:(KMDatePicker *)datePicker didSelectDate:(KMDatePickerDateModel *)datePickerDate { 79 NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@ %@", 80 datePickerDate.year, 81 datePickerDate.month, 82 datePickerDate.day, 83 datePickerDate.hour, 84 datePickerDate.minute, 85 datePickerDate.weekdayName 86 ]; 87 _txtFCurrent.text = dateStr; 88 } 89 90 @end
Main.storyboard
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> 3 <dependencies> 4 <deployment identifier="iOS"/> 5 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/> 6 </dependencies> 7 <scenes> 8 <!--View Controller--> 9 <scene sceneID="tne-QT-ifu"> 10 <objects> 11 <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"> 12 <layoutGuides> 13 <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> 14 <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> 15 </layoutGuides> 16 <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> 17 <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> 18 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> 19 <subviews> 20 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="YearMonthDayHourMinute" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="RU4-aD-bI3"> 21 <rect key="frame" x="180" y="58" width="240" height="30"/> 22 <animations/> 23 <constraints> 24 <constraint firstAttribute="width" constant="240" id="9Oi-OR-Ru9"/> 25 <constraint firstAttribute="height" constant="30" id="Wsa-Pd-EDg"/> 26 </constraints> 27 <fontDescription key="fontDescription" type="system" pointSize="14"/> 28 <textInputTraits key="textInputTraits"/> 29 </textField> 30 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="MonthDayHourMinute" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="KFz-2Q-yIQ"> 31 <rect key="frame" x="180" y="170" width="240" height="30"/> 32 <animations/> 33 <constraints> 34 <constraint firstAttribute="height" constant="30" id="Qxz-uf-Ngd"/> 35 <constraint firstAttribute="width" constant="240" id="pTd-xH-c6N"/> 36 </constraints> 37 <fontDescription key="fontDescription" type="system" pointSize="14"/> 38 <textInputTraits key="textInputTraits"/> 39 </textField> 40 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="YearMonthDay" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="V6m-6E-ZuV"> 41 <rect key="frame" x="180" y="113" width="240" height="30"/> 42 <animations/> 43 <constraints> 44 <constraint firstAttribute="height" constant="30" id="CzE-ap-TTQ"/> 45 <constraint firstAttribute="width" constant="240" id="eCi-kT-2tg"/> 46 </constraints> 47 <fontDescription key="fontDescription" type="system" pointSize="14"/> 48 <textInputTraits key="textInputTraits"/> 49 </textField> 50 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="HourMinute" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Neu-Vj-fG0"> 51 <rect key="frame" x="180" y="228" width="240" height="30"/> 52 <animations/> 53 <constraints> 54 <constraint firstAttribute="width" constant="240" id="XBx-GA-ad2"/> 55 <constraint firstAttribute="height" constant="30" id="tON-2M-EMP"/> 56 </constraints> 57 <fontDescription key="fontDescription" type="system" pointSize="14"/> 58 <textInputTraits key="textInputTraits"/> 59 </textField> 60 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="LimitedDate" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vt1-Aj-i6Y"> 61 <rect key="frame" x="180" y="280" width="240" height="30"/> 62 <animations/> 63 <constraints> 64 <constraint firstAttribute="height" constant="30" id="QSC-Me-tpx"/> 65 <constraint firstAttribute="width" constant="240" id="X0a-1i-Z2T"/> 66 </constraints> 67 <fontDescription key="fontDescription" type="system" pointSize="14"/> 68 <textInputTraits key="textInputTraits"/> 69 </textField> 70 </subviews> 71 <animations/> 72 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> 73 <constraints> 74 <constraint firstItem="Neu-Vj-fG0" firstAttribute="top" secondItem="KFz-2Q-yIQ" secondAttribute="bottom" constant="28" id="4Wp-rC-NJF"/> 75 <constraint firstItem="RU4-aD-bI3" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="38" id="EU7-1f-tVl"/> 76 <constraint firstItem="RU4-aD-bI3" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="FUG-e6-Qhi"/> 77 <constraint firstItem="Neu-Vj-fG0" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="HRH-7N-oaY"/> 78 <constraint firstItem="V6m-6E-ZuV" firstAttribute="top" secondItem="RU4-aD-bI3" secondAttribute="bottom" constant="25" id="Ind-TZ-Rzm"/> 79 <constraint firstItem="V6m-6E-ZuV" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="JTW-zd-LlI"/> 80 <constraint firstItem="KFz-2Q-yIQ" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="LpF-Jq-wwJ"/> 81 <constraint firstItem="KFz-2Q-yIQ" firstAttribute="top" secondItem="V6m-6E-ZuV" secondAttribute="bottom" constant="27" id="TyY-DA-rn2"/> 82 <constraint firstItem="vt1-Aj-i6Y" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="g0Z-bZ-p3g"/> 83 <constraint firstItem="vt1-Aj-i6Y" firstAttribute="top" secondItem="Neu-Vj-fG0" secondAttribute="bottom" constant="22" id="tyA-YZ-slJ"/> 84 </constraints> 85 </view> 86 <connections> 87 <outlet property="txtFHourMinute" destination="Neu-Vj-fG0" id="wPd-UK-nh5"/> 88 <outlet property="txtFLimitedDate" destination="vt1-Aj-i6Y" id="MzT-tx-thY"/> 89 <outlet property="txtFMonthDayHourMinute" destination="KFz-2Q-yIQ" id="Hp6-Ve-tYI"/> 90 <outlet property="txtFYearMonthDay" destination="V6m-6E-ZuV" id="0cJ-v8-xh3"/> 91 <outlet property="txtFYearMonthDayHourMinute" destination="RU4-aD-bI3" id="neo-JQ-wV5"/> 92 </connections> 93 </viewController> 94 <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> 95 </objects> 96 </scene> 97 </scenes> 98 </document>
NSDate+CalculateDay.h
1 #import <Foundation/Foundation.h> 2 3 @interface NSDate (CalculateDay) 4 5 /** 6 * 获取对应月份的天数 7 * 8 * @return 对应月份的天数 9 */ 10 - (NSUInteger)km_daysOfMonth; 11 12 /** 13 * 获取对应年份的天数 14 * 15 * @return 对应年份的天数 16 */ 17 - (NSUInteger)km_daysOfYear; 18 19 /** 20 * 获取对应月份的第一天时间 21 * 22 * @return 对应月份的第一天时间 23 */ 24 - (NSDate *)km_firstDayOfMonth; 25 26 /** 27 * 获取对应月份的最后一天时间 28 * 29 * @return 对应月份的最后一天时间 30 */ 31 - (NSDate *)km_lastDayOfMonth; 32 33 /** 34 * 根据月数和天数间隔,获取间隔后的时间 35 * 36 * @param months 月数间隔 37 * @param days 天数间隔 38 * 39 * @return 间隔后的时间 40 */ 41 - (NSDate *)km_addMonthAndDay:(NSUInteger)months days:(NSUInteger)days; 42 43 /** 44 * 根据开始时间和结束时间,获取间隔的时间数组 45 * 46 * @param toDate 结束时间 47 * 48 * @return 间隔的时间数组(月数和天数;toDate-fromDate的比较值是有符号整数NSInteger,所以存在负数的可能) 49 */ 50 - (NSArray *)km_monthAndDayBetweenTwoDates:(NSDate *)toDate; 51 52 /** 53 * 获取对应周期的数字 54 * 55 * @return 对应周期的数字(1:周日、2:周一、3:周二、4:周三、5:周四、6:周五、7:周六) 56 */ 57 - (NSInteger)km_weekday; 58 59 /** 60 * 根据地区标示符,获取对应周期的名称 61 * 62 * @param isShortName 是否是短名称 63 * @param localeIdentifier 地区标示符(中国:zh_CN、美国:en_US) 64 * 65 * @return 对应周期的名称 66 */ 67 - (NSString *)km_weekdayName:(BOOL)isShortName localeIdentifier:(NSString *)localeIdentifier; 68 69 /** 70 * 获取对应周期的中文名称 71 * 72 * @param isShortName 是否是短名称 73 * 74 * @return 对应周期的中文名称(短名称:周日、周一、周二、周三、周四、周五、周六)(长名称:星期日、星期一、星期二、星期三、星期四、星期五、星期六) 75 */ 76 - (NSString *)km_weekdayNameCN:(BOOL)isShortName; 77 78 /** 79 * 获取对应周期的英文名称 80 * 81 * @param isShortName 是否是短名称 82 * 83 * @return 对应周期的英文名称(短名称:Sun、Mon、Tue、Wed、Thu、Fri、Sat)(长名称:Sunday、Monday、Tuesday、Wednesday、Thursday、Friday、Saturday) 84 */ 85 - (NSString *)km_weekdayNameEN:(BOOL)isShortName; 86 87 @end
NSDate+CalculateDay.m
1 #import "NSDate+CalculateDay.h" 2 3 @implementation NSDate (CalculateDay) 4 5 - (NSUInteger)km_daysOfMonth { 6 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 7 NSRange range = [gregorian rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:self]; 8 return range.length; 9 } 10 11 - (NSUInteger)km_daysOfYear { 12 NSUInteger days = 0; 13 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 14 NSDateComponents *comps = [gregorian components:NSCalendarUnitYear fromDate:self]; 15 16 for (NSUInteger i=1; i<=12; i++) { 17 [comps setMonth:i]; 18 days += [[gregorian dateFromComponents:comps] km_daysOfMonth]; 19 } 20 return days; 21 } 22 23 - (NSDate *)km_firstDayOfMonth { 24 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 25 unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; 26 NSDateComponents *comps = [gregorian components:unitFlags fromDate:self]; 27 [comps setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // 使用UTC或GMT解决时区相差8小时的问题 28 [comps setDay:1]; 29 30 return [gregorian dateFromComponents:comps]; 31 } 32 33 - (NSDate *)km_lastDayOfMonth { 34 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 35 unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; 36 NSDateComponents *comps = [gregorian components:unitFlags fromDate:self]; 37 [comps setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // 使用UTC或GMT解决时区相差8小时的问题 38 [comps setDay:[self km_daysOfMonth]]; 39 40 return [gregorian dateFromComponents:comps]; 41 } 42 43 - (NSDate *)km_addMonthAndDay:(NSUInteger)months days:(NSUInteger)days { 44 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 45 NSDateComponents *comps = [NSDateComponents new]; 46 [comps setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // 使用UTC或GMT解决时区相差8小时的问题 47 [comps setMonth:months]; 48 [comps setDay:days]; 49 50 return [gregorian dateByAddingComponents:comps toDate:self options:0]; 51 } 52 53 - (NSArray *)km_monthAndDayBetweenTwoDates:(NSDate *)toDate { 54 NSMutableArray *mArrMonthAndDay = [[NSMutableArray alloc] initWithCapacity:2]; 55 NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 56 unsigned unitFlags = NSCalendarUnitMonth | NSCalendarUnitDay; 57 NSDateComponents *comps = [gregorian components:unitFlags fromDate:self toDate:toDate options:0]; 58 59 [mArrMonthAndDay addObject:[NSString stringWithFormat:@"%ld", (long)[comps month]]]; 60 [mArrMonthAndDay addObject:[NSString stringWithFormat:@"%ld", (long)[comps day]]]; 61 return mArrMonthAndDay; 62 } 63 64 - (NSInteger)km_weekday { 65 return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekday fromDate:self] weekday]; 66 } 67 68 - (NSString *)km_weekdayName:(BOOL)isShortName localeIdentifier:(NSString *)localeIdentifier { 69 NSDateFormatter *formatter = [NSDateFormatter new]; 70 formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; 71 formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:localeIdentifier]; 72 formatter.dateFormat = isShortName ? @"EE" : @"EEEE"; 73 return [formatter stringFromDate:self]; 74 } 75 76 - (NSString *)km_weekdayNameCN:(BOOL)isShortName { 77 /* 78 // 方法一: 79 NSArray *arrWeekdayName = 80 isShortName 81 ? @[ @"周日", 82 @"周一", 83 @"周二", 84 @"周三", 85 @"周四", 86 @"周五", 87 @"周六" ] 88 : @[ 89 @"星期日", 90 @"星期一", 91 @"星期二", 92 @"星期三", 93 @"星期四", 94 @"星期五", 95 @"星期六" 96 ]; 97 98 NSInteger weekday = [self weekday]; 99 return arrWeekdayName[weekday - 1]; 100 */ 101 102 // 方法二: 103 return [self km_weekdayName:isShortName localeIdentifier:@"zh_CN"]; 104 } 105 106 - (NSString *)km_weekdayNameEN:(BOOL)isShortName { 107 return [self km_weekdayName:isShortName localeIdentifier:@"en_US"]; 108 } 109 110 @end
DateHelper.h
1 #import <Foundation/Foundation.h> 2 3 @interface DateHelper : NSObject 4 /** 5 * 获取本地当前时间 6 * 7 * @return 本地当前时间 8 */ 9 + (NSDate *)localeDate; 10 11 /** 12 * 根据时间字符串和其格式,获取对应的时间 13 * 14 * @param dateStr 时间字符串 15 * @param format 时间字符串格式(默认值为@"yyyy-MM-dd HH:mm") 16 * 17 * @return 对应的时间 18 */ 19 + (NSDate *)dateFromString:(NSString *)dateStr withFormat:(NSString *)format; 20 21 /** 22 * 根据时间和其格式,获取对应的时间字符串 23 * 24 * @param date 时间 25 * @param format 时间字符串格式(默认值为@"yyyy-MM-dd HH:mm") 26 * 27 * @return 对应的时间字符串 28 */ 29 + (NSString *)dateToString:(NSDate *)date withFormat:(NSString *)format; 30 31 @end
DateHelper.m
1 #import "DateHelper.h" 2 3 @implementation DateHelper 4 5 + (NSDate *)localeDate { 6 NSDate *date = [NSDate date]; 7 NSTimeZone *zone = [NSTimeZone systemTimeZone]; 8 NSInteger interval = [zone secondsFromGMTForDate:date]; 9 return [date dateByAddingTimeInterval:interval]; 10 } 11 12 + (NSDate *)dateFromString:(NSString *)dateStr withFormat:(NSString *)format { 13 NSDateFormatter *formatter = [NSDateFormatter new]; 14 formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; 15 formatter.dateFormat = format ?: @"yyyy-MM-dd HH:mm"; 16 return [formatter dateFromString:dateStr]; 17 } 18 19 + (NSString *)dateToString:(NSDate *)date withFormat:(NSString *)format { 20 NSDateFormatter *formatter = [NSDateFormatter new]; 21 formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; 22 formatter.dateFormat = format ?: @"yyyy-MM-dd HH:mm"; 23 return [formatter stringFromDate:date]; 24 } 25 26 @end
KMDatePickerDateModel.h
1 #import <Foundation/Foundation.h> 2 3 @interface KMDatePickerDateModel : NSObject 4 @property (copy, nonatomic) NSString *year; 5 @property (copy, nonatomic) NSString *month; 6 @property (copy, nonatomic) NSString *day; 7 @property (copy, nonatomic) NSString *hour; 8 @property (copy, nonatomic) NSString *minute; 9 @property (copy, nonatomic) NSString *weekdayName; 10 11 - (instancetype)initWithDate:(NSDate *)date; 12 13 @end
KMDatePickerDateModel.m
1 #import "KMDatePickerDateModel.h" 2 #import "NSDate+CalculateDay.h" 3 4 @implementation KMDatePickerDateModel 5 6 - (instancetype)initWithDate:(NSDate *)date { 7 if (self = [super init]) { 8 NSDateFormatter *formatter = [NSDateFormatter new]; 9 formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; 10 formatter.dateFormat = @"yyyyMMddHHmm"; 11 NSString *dateStr = [formatter stringFromDate:date]; 12 13 _year = [dateStr substringWithRange:NSMakeRange(0, 4)]; 14 _month = [dateStr substringWithRange:NSMakeRange(4, 2)]; 15 _day = [dateStr substringWithRange:NSMakeRange(6, 2)]; 16 _hour = [dateStr substringWithRange:NSMakeRange(8, 2)]; 17 _minute = [dateStr substringWithRange:NSMakeRange(10, 2)]; 18 _weekdayName = [date km_weekdayNameCN:YES]; 19 } 20 return self; 21 } 22 23 @end
KMDatePicker.h
1 #import <UIKit/UIKit.h> 2 #import "KMDatePickerDateModel.h" 3 4 typedef NS_ENUM(NSUInteger, KMDatePickerStyle) { 5 KMDatePickerStyleYearMonthDayHourMinute, 6 KMDatePickerStyleYearMonthDay, 7 KMDatePickerStyleMonthDayHourMinute, 8 KMDatePickerStyleHourMinute 9 }; 10 11 @protocol KMDatePickerDelegate; 12 @interface KMDatePicker : UIView <UIPickerViewDataSource, UIPickerViewDelegate> 13 @property (nonatomic, weak) id<KMDatePickerDelegate> delegate; 14 @property (nonatomic, assign) KMDatePickerStyle datePickerStyle; 15 @property (nonatomic, strong) NSDate *minLimitedDate; ///< 最小限制时间;默认值为1970-01-01 00:00 16 @property (nonatomic, strong) NSDate *maxLimitedDate; ///< 最大限制时间;默认值为2060-12-31 23:59 17 @property (nonatomic, strong) NSDate *defaultLimitedDate; ///< 默认限制时间;默认值为最小限制时间,当选择时间不在指定范围,就滚动到此默认限制时间 18 @property (nonatomic, strong) NSDate *scrollToDate; ///< 滚动到指定时间;默认值为当前时间 19 20 - (instancetype)initWithFrame:(CGRect)frame delegate:(id<KMDatePickerDelegate>)delegate datePickerStyle:(KMDatePickerStyle)datePickerStyle; 21 22 @end 23 24 @protocol KMDatePickerDelegate <NSObject> 25 @required 26 - (void)datePicker:(KMDatePicker *)datePicker didSelectDate:(KMDatePickerDateModel *)datePickerDate; 27 28 @end
KMDatePicker.m
1 #import "KMDatePicker.h" 2 #import "NSDate+CalculateDay.h" 3 #import "DateHelper.h" 4 5 #define kDefaultMinLimitedDate @"1970-01-01 00:00" 6 #define kDefaultMaxLimitedDate @"2060-12-31 23:59" 7 #define kMonthCountOfEveryYear 12 8 #define kHourCountOfEveryDay 24 9 #define kMinuteCountOfEveryHour 60 10 #define kRowDisabledStatusColor [UIColor redColor] 11 #define kRowNormalStatusColor [UIColor blackColor] 12 #define kWidthOfTotal self.frame.size.width 13 #define kHeightOfButtonContentView 35.0 14 #define kButtonNormalStatusColor [UIColor colorWithRed:0.0 green:0.5 blue:1.0 alpha:1.0] 15 16 @interface KMDatePicker () { 17 UIPickerView *_pikV; 18 19 // 最小和最大限制时间、滚动到指定时间实体对象实例 20 KMDatePickerDateModel *_datePickerDateMinLimited; 21 KMDatePickerDateModel *_datePickerDateMaxLimited; 22 KMDatePickerDateModel *_datePickerDateScrollTo; 23 24 // 存储时间数据源的数组 25 NSMutableArray *_mArrYear; 26 NSMutableArray *_mArrMonth; 27 NSMutableArray *_mArrDay; 28 NSMutableArray *_mArrHour; 29 NSMutableArray *_mArrMinute; 30 31 // 时间数据源的数组中,选中元素的索引 32 NSInteger _yearIndex; 33 NSInteger _monthIndex; 34 NSInteger _dayIndex; 35 NSInteger _hourIndex; 36 NSInteger _minuteIndex; 37 } 38 39 @end 40 41 @implementation KMDatePicker 42 43 - (instancetype)init { 44 if (self = [super init]) { 45 self.backgroundColor = [UIColor whiteColor]; 46 } 47 return self; 48 } 49 50 - (instancetype)initWithFrame:(CGRect)frame { 51 if (self = [super initWithFrame:frame]) { 52 self.backgroundColor = [UIColor whiteColor]; 53 } 54 return self; 55 } 56 57 - (instancetype)initWithFrame:(CGRect)frame delegate:(id<KMDatePickerDelegate>)delegate datePickerStyle:(KMDatePickerStyle)datePickerStyle { 58 _delegate = delegate; 59 _datePickerStyle = datePickerStyle; 60 return [self initWithFrame:frame]; 61 } 62 63 #pragma mark - 重写属性 64 - (void)setMinLimitedDate:(NSDate *)minLimitedDate { 65 _minLimitedDate = minLimitedDate; 66 if (_minLimitedDate && !_defaultLimitedDate) { 67 _defaultLimitedDate = _minLimitedDate; 68 } 69 } 70 71 #pragma mark - 自定义方法 72 - (void)addUnitLabel:(NSString *)text withPointX:(CGFloat)pointX { 73 CGFloat pointY = _pikV.frame.size.height/2 - 10.0 + kHeightOfButtonContentView; 74 UILabel *lblUnit = [[UILabel alloc] initWithFrame:CGRectMake(pointX, pointY, 20.0, 20.0)]; 75 lblUnit.text = text; 76 lblUnit.textAlignment = NSTextAlignmentCenter; 77 lblUnit.textColor = [UIColor blackColor]; 78 lblUnit.backgroundColor = [UIColor clearColor]; 79 lblUnit.font = [UIFont systemFontOfSize:18.0]; 80 lblUnit.layer.shadowColor = [[UIColor whiteColor] CGColor]; 81 lblUnit.layer.shadowOpacity = 0.5; 82 lblUnit.layer.shadowRadius = 5.0; 83 [self addSubview:lblUnit]; 84 } 85 86 - (NSUInteger)daysOfMonth { 87 NSString *dateStr = [NSString stringWithFormat:@"%@-%@-01 00:00", _mArrYear[_yearIndex], _mArrMonth[_monthIndex]]; 88 return [[DateHelper dateFromString:dateStr withFormat:@"yyyy-MM-dd HH:mm"] km_daysOfMonth]; 89 } 90 91 - (void)reloadDayArray { 92 _mArrDay = [NSMutableArray new]; 93 for (NSUInteger i=1, len=[self daysOfMonth]; i<=len; i++) { 94 [_mArrDay addObject:[NSString stringWithFormat:@"%02ld", (long)i]]; 95 } 96 } 97 98 - (void)loadData { 99 // 初始化最小和最大限制时间、滚动到指定时间实体对象实例 100 if (!_minLimitedDate) { 101 _minLimitedDate = [DateHelper dateFromString:kDefaultMinLimitedDate withFormat:nil]; 102 } 103 _datePickerDateMinLimited = [[KMDatePickerDateModel alloc] initWithDate:_minLimitedDate]; 104 105 if (!_maxLimitedDate) { 106 _maxLimitedDate = [DateHelper dateFromString:kDefaultMaxLimitedDate withFormat:nil]; 107 } 108 _datePickerDateMaxLimited = [[KMDatePickerDateModel alloc] initWithDate:_maxLimitedDate]; 109 110 // 滚动到指定时间;默认值为当前时间。如果是使用自定义时间小于最小限制时间,这时就以最小限制时间为准;如果是使用自定义时间大于最大限制时间,这时就以最大限制时间为准 111 if (!_scrollToDate) { 112 _scrollToDate = [DateHelper localeDate]; 113 } 114 if ([_scrollToDate compare:_minLimitedDate] == NSOrderedAscending) { 115 _scrollToDate = _minLimitedDate; 116 } else if ([_scrollToDate compare:_maxLimitedDate] == NSOrderedDescending) { 117 _scrollToDate = _maxLimitedDate; 118 } 119 _datePickerDateScrollTo = [[KMDatePickerDateModel alloc] initWithDate:_scrollToDate]; 120 121 // 初始化存储时间数据源的数组 122 // 年 123 _mArrYear = [NSMutableArray new]; 124 for (NSInteger beginVal=[_datePickerDateMinLimited.year integerValue], endVal=[_datePickerDateMaxLimited.year integerValue]; beginVal<=endVal; beginVal++) { 125 [_mArrYear addObject:[NSString stringWithFormat:@"%ld", (long)beginVal]]; 126 } 127 _yearIndex = [_datePickerDateScrollTo.year integerValue] - [_datePickerDateMinLimited.year integerValue]; 128 129 // 月 130 _mArrMonth = [[NSMutableArray alloc] initWithCapacity:kMonthCountOfEveryYear]; 131 for (NSInteger i=1; i<=kMonthCountOfEveryYear; i++) { 132 [_mArrMonth addObject:[NSString stringWithFormat:@"%02ld", (long)i]]; 133 } 134 _monthIndex = [_datePickerDateScrollTo.month integerValue] - 1; 135 136 // 日 137 [self reloadDayArray]; 138 _dayIndex = [_datePickerDateScrollTo.day integerValue] - 1; 139 140 // 时 141 _mArrHour = [[NSMutableArray alloc] initWithCapacity:kHourCountOfEveryDay]; 142 for (NSInteger i=0; i<kHourCountOfEveryDay; i++) { 143 [_mArrHour addObject:[NSString stringWithFormat:@"%02ld", (long)i]]; 144 } 145 _hourIndex = [_datePickerDateScrollTo.hour integerValue]; 146 147 // 分 148 _mArrMinute = [[NSMutableArray alloc] initWithCapacity:kMinuteCountOfEveryHour]; 149 for (NSInteger i=0; i<kMinuteCountOfEveryHour; i++) { 150 [_mArrMinute addObject:[NSString stringWithFormat:@"%02ld", (long)i]]; 151 } 152 _minuteIndex = [_datePickerDateScrollTo.minute integerValue]; 153 } 154 155 - (void)scrollToDateIndexPosition { 156 NSArray *arrIndex; 157 switch (_datePickerStyle) { 158 case KMDatePickerStyleYearMonthDayHourMinute: { 159 arrIndex = @[ 160 [NSNumber numberWithInteger:_yearIndex], 161 [NSNumber numberWithInteger:_monthIndex], 162 [NSNumber numberWithInteger:_dayIndex], 163 [NSNumber numberWithInteger:_hourIndex], 164 [NSNumber numberWithInteger:_minuteIndex] 165 ]; 166 break; 167 } 168 case KMDatePickerStyleYearMonthDay: { 169 arrIndex = @[ 170 [NSNumber numberWithInteger:_yearIndex], 171 [NSNumber numberWithInteger:_monthIndex], 172 [NSNumber numberWithInteger:_dayIndex] 173 ]; 174 break; 175 } 176 case KMDatePickerStyleMonthDayHourMinute: { 177 arrIndex = @[ 178 [NSNumber numberWithInteger:_monthIndex], 179 [NSNumber numberWithInteger:_dayIndex], 180 [NSNumber numberWithInteger:_hourIndex], 181 [NSNumber numberWithInteger:_minuteIndex] 182 ]; 183 break; 184 } 185 case KMDatePickerStyleHourMinute: { 186 arrIndex = @[ 187 [NSNumber numberWithInteger:_hourIndex], 188 [NSNumber numberWithInteger:_minuteIndex] 189 ]; 190 break; 191 } 192 } 193 194 for (NSUInteger i=0, len=arrIndex.count; i<len; i++) { 195 [_pikV selectRow:[arrIndex[i] integerValue] inComponent:i animated:YES]; 196 } 197 } 198 199 - (BOOL)validatedDate:(NSDate *)date { 200 NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@", 201 _datePickerDateMinLimited.year, 202 _datePickerDateMinLimited.month, 203 _datePickerDateMinLimited.day, 204 _datePickerDateMinLimited.hour, 205 _datePickerDateMinLimited.minute 206 ]; 207 208 return !([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending || 209 [date compare:_maxLimitedDate] == NSOrderedDescending); 210 } 211 212 - (BOOL)canShowScrollToNowButton { 213 return [self validatedDate:[DateHelper localeDate]]; 214 } 215 216 - (void)cancel:(UIButton *)sender { 217 UIViewController *delegateVC = (UIViewController *)self.delegate; 218 [delegateVC.view endEditing:YES]; 219 } 220 221 - (void)scrollToNowDateIndexPosition:(UIButton *)sender { 222 [self scrollToDateIndexPositionWithDate:[DateHelper localeDate]]; 223 } 224 225 - (void)scrollToDateIndexPositionWithDate:(NSDate *)date { 226 // 为了区别最大最小限制范围外行的标签颜色,这里需要重新加载所有组件列 227 [_pikV reloadAllComponents]; 228 229 _scrollToDate = date; 230 _datePickerDateScrollTo = [[KMDatePickerDateModel alloc] initWithDate:_scrollToDate]; 231 _yearIndex = [_datePickerDateScrollTo.year integerValue] - [_datePickerDateMinLimited.year integerValue]; 232 _monthIndex = [_datePickerDateScrollTo.month integerValue] - 1; 233 _dayIndex = [_datePickerDateScrollTo.day integerValue] - 1; 234 _hourIndex = [_datePickerDateScrollTo.hour integerValue]; 235 _minuteIndex = [_datePickerDateScrollTo.minute integerValue]; 236 [self scrollToDateIndexPosition]; 237 } 238 239 - (void)confirm:(UIButton *)sender { 240 [self playDelegateAfterSelectedRow]; 241 242 [self cancel:sender]; 243 } 244 245 - (UIColor *)monthRowTextColor:(NSInteger)row { 246 UIColor *color = kRowNormalStatusColor; 247 NSString *dateStr = [NSString stringWithFormat:@"%@-%@-01 00:00", 248 _mArrYear[_yearIndex], 249 _mArrMonth[row] 250 ]; 251 NSDate *date = [DateHelper dateFromString:dateStr withFormat:nil]; 252 253 NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-01 00:00", 254 _datePickerDateMinLimited.year, 255 _datePickerDateMinLimited.month 256 ]; 257 258 if ([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending || 259 [date compare:_maxLimitedDate] == NSOrderedDescending) { 260 color = kRowDisabledStatusColor; 261 } 262 263 return color; 264 } 265 266 - (UIColor *)dayRowTextColor:(NSInteger)row { 267 UIColor *color = kRowNormalStatusColor; 268 NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ 00:00", 269 _mArrYear[_yearIndex], 270 _mArrMonth[_monthIndex], 271 _mArrDay[row] 272 ]; 273 NSDate *date = [DateHelper dateFromString:dateStr withFormat:nil]; 274 275 NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ 00:00", 276 _datePickerDateMinLimited.year, 277 _datePickerDateMinLimited.month, 278 _datePickerDateMinLimited.day 279 ]; 280 281 if ([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending || 282 [date compare:_maxLimitedDate] == NSOrderedDescending) { 283 color = kRowDisabledStatusColor; 284 } 285 286 return color; 287 } 288 289 - (UIColor *)hourRowTextColor:(NSInteger)row { 290 UIColor *color = kRowNormalStatusColor; 291 NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:00", 292 _mArrYear[_yearIndex], 293 _mArrMonth[_monthIndex], 294 _mArrDay[_dayIndex], 295 _mArrHour[row] 296 ]; 297 NSDate *date = [DateHelper dateFromString:dateStr withFormat:nil]; 298 299 NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:00", 300 _datePickerDateMinLimited.year, 301 _datePickerDateMinLimited.month, 302 _datePickerDateMinLimited.day, 303 _datePickerDateMinLimited.hour 304 ]; 305 306 if ([date compare:[DateHelper dateFromString:minDateStr withFormat:nil]] == NSOrderedAscending || 307 [date compare:_maxLimitedDate] == NSOrderedDescending) { 308 color = kRowDisabledStatusColor; 309 } 310 311 return color; 312 } 313 314 - (UIColor *)minuteRowTextColor:(NSInteger)row { 315 NSString *format = @"yyyy-MM-dd HH:mm:ss"; 316 UIColor *color = kRowNormalStatusColor; 317 NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@:00", 318 _mArrYear[_yearIndex], 319 _mArrMonth[_monthIndex], 320 _mArrDay[_dayIndex], 321 _mArrHour[_hourIndex], 322 _mArrMinute[row] 323 ]; 324 NSDate *date = [DateHelper dateFromString:dateStr withFormat:format]; 325 326 NSString *minDateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@:00", 327 _datePickerDateMinLimited.year, 328 _datePickerDateMinLimited.month, 329 _datePickerDateMinLimited.day, 330 _datePickerDateMinLimited.hour, 331 _datePickerDateMinLimited.minute 332 ]; 333 334 if ([date compare:[DateHelper dateFromString:minDateStr withFormat:format]] == NSOrderedAscending || 335 [date compare:_maxLimitedDate] == NSOrderedDescending) { 336 color = kRowDisabledStatusColor; 337 } 338 339 return color; 340 } 341 342 #pragma mark - 绘制内容 343 - (void)drawRect:(CGRect)rect { 344 // 加载数据 345 [self loadData]; 346 347 // 初始化头部按钮(取消、现在时间、确定) 348 UIView *buttonContentView = [[UIView alloc] initWithFrame:CGRectMake(-2.0, 0.0, kWidthOfTotal + 4.0, kHeightOfButtonContentView)]; 349 buttonContentView.layer.borderColor = [UIColor lightGrayColor].CGColor; 350 buttonContentView.layer.borderWidth = 0.5; 351 [self addSubview:buttonContentView]; 352 353 UIButton *btnCancel = [UIButton buttonWithType:UIButtonTypeCustom]; 354 btnCancel.frame = CGRectMake(2.0, 2.5, 60.0, kHeightOfButtonContentView - 5.0); 355 btnCancel.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; 356 [btnCancel setTitle:@"取消" forState:UIControlStateNormal]; 357 [btnCancel setTitleColor:kButtonNormalStatusColor forState:UIControlStateNormal]; 358 [btnCancel addTarget:self 359 action:@selector(cancel:) 360 forControlEvents:UIControlEventTouchUpInside]; 361 [buttonContentView addSubview:btnCancel]; 362 363 if ([self canShowScrollToNowButton]) { 364 UIButton *btnScrollToNow = [UIButton buttonWithType:UIButtonTypeCustom]; 365 btnScrollToNow.frame = CGRectMake(buttonContentView.frame.size.width/2 - 50.0, 2.5, 100.0, kHeightOfButtonContentView - 5.0); 366 btnScrollToNow.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; 367 [btnScrollToNow setTitle:@"现在时间" forState:UIControlStateNormal]; 368 [btnScrollToNow setTitleColor:kButtonNormalStatusColor forState:UIControlStateNormal]; 369 [btnScrollToNow addTarget:self 370 action:@selector(scrollToNowDateIndexPosition:) 371 forControlEvents:UIControlEventTouchUpInside]; 372 [buttonContentView addSubview:btnScrollToNow]; 373 } 374 375 UIButton *btnConfirm = [UIButton buttonWithType:UIButtonTypeCustom]; 376 btnConfirm.frame = CGRectMake(kWidthOfTotal - 58.0, 2.5, 60.0, kHeightOfButtonContentView - 5.0); 377 btnConfirm.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; 378 [btnConfirm setTitle:@"确定" forState:UIControlStateNormal]; 379 [btnConfirm setTitleColor:kButtonNormalStatusColor forState:UIControlStateNormal]; 380 [btnConfirm addTarget:self 381 action:@selector(confirm:) 382 forControlEvents:UIControlEventTouchUpInside]; 383 [buttonContentView addSubview:btnConfirm]; 384 385 // 初始化选择器视图控件 386 if (!_pikV) { 387 _pikV = [[UIPickerView alloc]initWithFrame:CGRectMake(0.0, kHeightOfButtonContentView, kWidthOfTotal, self.frame.size.height - kHeightOfButtonContentView)]; 388 _pikV.showsSelectionIndicator = YES; 389 _pikV.backgroundColor = [UIColor clearColor]; 390 [self addSubview:_pikV]; 391 } 392 _pikV.dataSource = self; 393 _pikV.delegate = self; 394 395 // 初始化滚动到指定时间位置 396 [self scrollToDateIndexPosition]; 397 } 398 399 #pragma mark - 执行 KMDatePickerDelegate 委托代理协议方法,用于回调传递参数 400 - (void)playDelegateAfterSelectedRow { 401 if ([self.delegate respondsToSelector:@selector(datePicker:didSelectDate:)]) { 402 [self.delegate datePicker:self 403 didSelectDate:_datePickerDateScrollTo]; 404 } 405 } 406 407 #pragma mark - UIPickerViewDataSource 408 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { 409 NSInteger numberOfComponents = 0; 410 switch (_datePickerStyle) { 411 case KMDatePickerStyleYearMonthDayHourMinute: { 412 numberOfComponents = 5; 413 break; 414 } 415 case KMDatePickerStyleYearMonthDay: { 416 numberOfComponents = 3; 417 break; 418 } 419 case KMDatePickerStyleMonthDayHourMinute: { 420 numberOfComponents = 4; 421 break; 422 } 423 case KMDatePickerStyleHourMinute: { 424 numberOfComponents = 2; 425 break; 426 } 427 } 428 return numberOfComponents; 429 } 430 431 - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { 432 NSInteger numberOfRows = 0; 433 switch (_datePickerStyle) { 434 case KMDatePickerStyleYearMonthDayHourMinute: { 435 switch (component) { 436 case 0: 437 numberOfRows = _mArrYear.count; 438 break; 439 case 1: 440 numberOfRows = kMonthCountOfEveryYear; 441 break; 442 case 2: 443 numberOfRows = [self daysOfMonth]; 444 break; 445 case 3: 446 numberOfRows = kHourCountOfEveryDay; 447 break; 448 case 4: 449 numberOfRows = kMinuteCountOfEveryHour; 450 break; 451 } 452 break; 453 } 454 case KMDatePickerStyleYearMonthDay: { 455 switch (component) { 456 case 0: 457 numberOfRows = _mArrYear.count; 458 break; 459 case 1: 460 numberOfRows = kMonthCountOfEveryYear; 461 break; 462 case 2: 463 numberOfRows = [self daysOfMonth]; 464 break; 465 } 466 break; 467 } 468 case KMDatePickerStyleMonthDayHourMinute: { 469 switch (component) { 470 case 0: 471 numberOfRows = kMonthCountOfEveryYear; 472 break; 473 case 1: 474 numberOfRows = [self daysOfMonth]; 475 break; 476 case 2: 477 numberOfRows = kHourCountOfEveryDay; 478 break; 479 case 3: 480 numberOfRows = kMinuteCountOfEveryHour; 481 break; 482 } 483 break; 484 } 485 case KMDatePickerStyleHourMinute: { 486 switch (component) { 487 case 0: 488 numberOfRows = kHourCountOfEveryDay; 489 break; 490 case 1: 491 numberOfRows = kMinuteCountOfEveryHour; 492 break; 493 } 494 break; 495 } 496 } 497 return numberOfRows; 498 } 499 500 #pragma mark - UIPickerViewDelegate 501 - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component { 502 CGFloat width = 50.0; 503 CGFloat widthOfAverage; 504 505 switch (_datePickerStyle) { 506 case KMDatePickerStyleYearMonthDayHourMinute: { 507 // 规则一:平均宽度 = (总共宽度 - 年份相比多两个数字的宽度 - 分钟会是右对齐导致需偏移宽度来显示「分」这个文字) / 5等份 508 widthOfAverage = (kWidthOfTotal - 20.0 - 25.0) / 5; 509 switch (component) { 510 case 0: 511 width = widthOfAverage + 20.0; 512 // 规则二:单位标签的 X 坐标位置 = 列的水平居中 X 坐标 + 偏移量 513 [self addUnitLabel:@"年" withPointX:width/2 + 24.0]; 514 break; 515 case 1: 516 width = widthOfAverage; 517 [self addUnitLabel:@"月" withPointX:(widthOfAverage + 20.0) + width/2 + 16.0]; 518 break; 519 case 2: 520 width = widthOfAverage; 521 [self addUnitLabel:@"日" withPointX:(2*widthOfAverage + 20.0) + width/2 + 22.0]; 522 break; 523 case 3: 524 width = widthOfAverage; 525 [self addUnitLabel:@"时" withPointX:(3*widthOfAverage + 20.0) + width/2 + 28.0]; 526 break; 527 case 4: 528 width = widthOfAverage; 529 [self addUnitLabel:@"分" withPointX:(4*widthOfAverage + 20.0) + width/2 + 32.0]; 530 break; 531 } 532 break; 533 } 534 case KMDatePickerStyleYearMonthDay: { 535 widthOfAverage = (kWidthOfTotal - 20.0 - 15.0) / 3; 536 switch (component) { 537 case 0: 538 width = widthOfAverage + 20.0; 539 [self addUnitLabel:@"年" withPointX:width/2 + 24.0]; 540 break; 541 case 1: 542 width = widthOfAverage; 543 [self addUnitLabel:@"月" withPointX:(widthOfAverage + 20.0) + width/2 + 16.0]; 544 break; 545 case 2: 546 width = widthOfAverage; 547 [self addUnitLabel:@"日" withPointX:(2*widthOfAverage + 20.0) + width/2 + 22.0]; 548 break; 549 } 550 break; 551 } 552 case KMDatePickerStyleMonthDayHourMinute: { 553 widthOfAverage = (kWidthOfTotal - 20.0) / 4; 554 switch (component) { 555 case 0: 556 width = widthOfAverage; 557 [self addUnitLabel:@"月" withPointX:width/2 + 11.0]; 558 break; 559 case 1: 560 width = widthOfAverage; 561 [self addUnitLabel:@"日" withPointX:widthOfAverage + width/2 + 17.0]; 562 break; 563 case 2: 564 width = widthOfAverage; 565 [self addUnitLabel:@"时" withPointX:2*widthOfAverage + width/2 + 23.0]; 566 break; 567 case 3: 568 width = widthOfAverage; 569 [self addUnitLabel:@"分" withPointX:3*widthOfAverage + width/2 + 27.0]; 570 break; 571 } 572 break; 573 } 574 case KMDatePickerStyleHourMinute: { 575 widthOfAverage = (kWidthOfTotal - 10.0) / 2; 576 switch (component) { 577 case 0: 578 width = widthOfAverage; 579 [self addUnitLabel:@"时" withPointX:width/2 + 12.0]; 580 break; 581 case 1: 582 width = widthOfAverage; 583 [self addUnitLabel:@"分" withPointX:widthOfAverage + width/2 + 18.0]; 584 break; 585 } 586 break; 587 } 588 } 589 return width; 590 } 591 592 - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component { 593 return 30.0; 594 } 595 596 - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view { 597 UILabel *lblCustom = (UILabel *)view; 598 if (!lblCustom) { 599 lblCustom = [UILabel new]; 600 lblCustom.textAlignment = NSTextAlignmentCenter; 601 lblCustom.font = [UIFont systemFontOfSize:18.0]; 602 } 603 604 NSString *text; 605 UIColor *textColor = kRowNormalStatusColor; 606 switch (_datePickerStyle) { 607 case KMDatePickerStyleYearMonthDayHourMinute: { 608 switch (component) { 609 case 0: 610 text = _mArrYear[row]; 611 break; 612 case 1: 613 text = _mArrMonth[row]; 614 textColor = [self monthRowTextColor:row]; 615 break; 616 case 2: 617 text = _mArrDay[row]; 618 textColor = [self dayRowTextColor:row]; 619 break; 620 case 3: 621 text = _mArrHour[row]; 622 textColor = [self hourRowTextColor:row]; 623 break; 624 case 4: 625 text = _mArrMinute[row]; 626 textColor = [self minuteRowTextColor:row]; 627 break; 628 } 629 break; 630 } 631 case KMDatePickerStyleYearMonthDay: { 632 switch (component) { 633 case 0: 634 text = _mArrYear[row]; 635 break; 636 case 1: 637 text = _mArrMonth[row]; 638 textColor = [self monthRowTextColor:row]; 639 break; 640 case 2: 641 text = _mArrDay[row]; 642 textColor = [self dayRowTextColor:row]; 643 break; 644 } 645 break; 646 } 647 case KMDatePickerStyleMonthDayHourMinute: { 648 switch (component) { 649 case 0: 650 text = _mArrMonth[row]; 651 textColor = [self monthRowTextColor:row]; 652 break; 653 case 1: 654 text = _mArrDay[row]; 655 textColor = [self dayRowTextColor:row]; 656 break; 657 case 2: 658 text = _mArrHour[row]; 659 textColor = [self hourRowTextColor:row]; 660 break; 661 case 3: 662 text = _mArrMinute[row]; 663 textColor = [self minuteRowTextColor:row]; 664 break; 665 } 666 break; 667 } 668 case KMDatePickerStyleHourMinute: { 669 switch (component) { 670 case 0: 671 text = _mArrHour[row]; 672 textColor = [self hourRowTextColor:row]; 673 break; 674 case 1: 675 text = _mArrMinute[row]; 676 textColor = [self minuteRowTextColor:row]; 677 break; 678 } 679 break; 680 } 681 } 682 lblCustom.text = text; 683 lblCustom.textColor = textColor; 684 return lblCustom; 685 } 686 687 - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 688 switch (_datePickerStyle) { 689 case KMDatePickerStyleYearMonthDayHourMinute: { 690 switch (component) { 691 case 0: 692 _yearIndex = row; 693 break; 694 case 1: 695 _monthIndex = row; 696 break; 697 case 2: 698 _dayIndex = row; 699 break; 700 case 3: 701 _hourIndex = row; 702 break; 703 case 4: 704 _minuteIndex = row; 705 break; 706 } 707 if (component == 0 || component == 1) { 708 [self reloadDayArray]; 709 if (_mArrDay.count-1 < _dayIndex) { 710 _dayIndex = _mArrDay.count-1; 711 } 712 } 713 break; 714 } 715 case KMDatePickerStyleYearMonthDay: { 716 switch (component) { 717 case 0: 718 _yearIndex = row; 719 break; 720 case 1: 721 _monthIndex = row; 722 break; 723 case 2: 724 _dayIndex = row; 725 break; 726 } 727 if (component == 0 || component == 1) { 728 [self reloadDayArray]; 729 if (_mArrDay.count-1 < _dayIndex) { 730 _dayIndex = _mArrDay.count-1; 731 } 732 } 733 break; 734 } 735 case KMDatePickerStyleMonthDayHourMinute: { 736 switch (component) { 737 case 0: 738 _monthIndex = row; 739 break; 740 case 1: 741 _dayIndex = row; 742 break; 743 case 2: 744 _hourIndex = row; 745 break; 746 case 3: 747 _minuteIndex = row; 748 break; 749 } 750 if (component == 0) { 751 [self reloadDayArray]; 752 if (_mArrDay.count-1 < _dayIndex) { 753 _dayIndex = _mArrDay.count-1; 754 } 755 } 756 break; 757 } 758 case KMDatePickerStyleHourMinute: { 759 switch (component) { 760 case 0: 761 _hourIndex = row; 762 break; 763 case 1: 764 _minuteIndex = row; 765 break; 766 } 767 break; 768 } 769 } 770 771 NSString *dateStr = [NSString stringWithFormat:@"%@-%@-%@ %@:%@", 772 _mArrYear[_yearIndex], 773 _mArrMonth[_monthIndex], 774 _mArrDay[_dayIndex], 775 _mArrHour[_hourIndex], 776 _mArrMinute[_minuteIndex] 777 ]; 778 _scrollToDate = [DateHelper dateFromString:dateStr withFormat:nil]; 779 _datePickerDateScrollTo = [[KMDatePickerDateModel alloc] initWithDate:_scrollToDate]; 780 781 // 为了区别最大最小限制范围外行的标签颜色,这里需要重新加载所有组件列 782 [pickerView reloadAllComponents]; 783 784 // 如果选择时间不在最小和最大限制时间范围内就滚动到有效的默认范围内 785 if (![self validatedDate:_scrollToDate]) { 786 [self scrollToDateIndexPositionWithDate:_defaultLimitedDate]; 787 } 788 } 789 790 @end
源码下载地址:
https://github.com/KenmuHuang/KMDatePicker
2016-04-06,已更新 GitHub 内容:添加默认限制时间属性;默认值为最小限制时间,当选择时间不在指定范围,就滚动到此默认限制时间;解决跨月份无法处理好限制的问题