├── Demo ├── .DS_Store └── JWDatePickerView │ ├── .DS_Store │ ├── JWDatePickerView.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── zhujianwei.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── xcuserdata │ │ └── zhujianwei.xcuserdatad │ │ │ ├── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── JWDatePickerView.xcscheme │ │ │ └── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ └── project.pbxproj │ └── JWDatePickerView │ ├── ViewController.h │ ├── JWDatePickerView.xcdatamodeld │ ├── .xccurrentversion │ └── JWDatePickerView.xcdatamodel │ │ └── contents │ ├── main.m │ ├── JWDatePickerView │ ├── KBDatePickerViewkeyBoard.h │ ├── JWDatePickerView.h │ ├── KBDatePickerViewkeyBoard.m │ └── JWDatePickerView.m │ ├── AppDelegate.h │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Info.plist │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── ViewController.m │ └── AppDelegate.m ├── Source ├── .DS_Store └── PickerView.gif ├── JWDatePickerView ├── KBDatePickerViewkeyBoard.h ├── JWDatePickerView.h ├── KBDatePickerViewkeyBoard.m └── JWDatePickerView.m ├── README.md └── JWDatePickerView-Swift ├── JWDatePickerKeyBoardView.swift ├── JWPickerKeyBoardView.swift └── JWDatePickerView.swift /Demo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubOfJW/JWDatePickerView/HEAD/Demo/.DS_Store -------------------------------------------------------------------------------- /Source/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubOfJW/JWDatePickerView/HEAD/Source/.DS_Store -------------------------------------------------------------------------------- /Source/PickerView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubOfJW/JWDatePickerView/HEAD/Source/PickerView.gif -------------------------------------------------------------------------------- /Demo/JWDatePickerView/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubOfJW/JWDatePickerView/HEAD/Demo/JWDatePickerView/.DS_Store -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView.xcodeproj/project.xcworkspace/xcuserdata/zhujianwei.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubOfJW/JWDatePickerView/HEAD/Demo/JWDatePickerView/JWDatePickerView.xcodeproj/project.xcworkspace/xcuserdata/zhujianwei.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/JWDatePickerView.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | JWDatePickerView.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/JWDatePickerView.xcdatamodeld/JWDatePickerView.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView.xcodeproj/xcuserdata/zhujianwei.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JWDatePickerView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 5BA28AD91D3DC2F300E4AFEA 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /JWDatePickerView/KBDatePickerViewkeyBoard.h: -------------------------------------------------------------------------------- 1 | // 2 | // KBSexkeyBoard.h 3 | // SunCarGuide 4 | // 5 | // Created by 朱建伟 on 15/12/17. 6 | // Copyright © 2015年 jryghq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "JWDatePickerView.h" 13 | 14 | @interface KBDatePickerViewkeyBoard : UIView 15 | 16 | /** 17 | * 快捷初始化 18 | */ 19 | -(instancetype)initWithFrame:(CGRect)frame title:(NSString*)title currentDayName:(NSString*)currentDayName; 20 | 21 | 22 | @property(nonatomic,strong,readonly)JWDatePickerView *pickerView; 23 | 24 | 25 | @property(nonatomic,copy)NSString *title; 26 | 27 | 28 | @property(nonatomic,copy)void(^didSelectedBlock)(NSDate *date,NSString* dateStr); 29 | 30 | 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/JWDatePickerView/KBDatePickerViewkeyBoard.h: -------------------------------------------------------------------------------- 1 | // 2 | // KBSexkeyBoard.h 3 | // SunCarGuide 4 | // 5 | // Created by 朱建伟 on 15/12/17. 6 | // Copyright © 2015年 jryghq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "JWDatePickerView.h" 13 | 14 | @interface KBDatePickerViewkeyBoard : UIView 15 | 16 | /** 17 | * 快捷初始化 18 | */ 19 | -(instancetype)initWithFrame:(CGRect)frame title:(NSString*)title currentDayName:(NSString*)currentDayName; 20 | 21 | 22 | @property(nonatomic,strong,readonly)JWDatePickerView *pickerView; 23 | 24 | 25 | @property(nonatomic,copy)NSString *title; 26 | 27 | 28 | @property(nonatomic,copy)void(^didSelectedBlock)(NSDate *date,NSString* dateStr); 29 | 30 | 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (strong, nonatomic) UIWindow *window; 15 | 16 | @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; 17 | @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; 18 | @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; 19 | 20 | - (void)saveContext; 21 | - (NSURL *)applicationDocumentsDirectory; 22 | 23 | 24 | @end 25 | 26 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JWDatePickerView 2 | 3 | 4 | ====介绍:本控件是为了扩展苹果的日历控件而编写, 5 | 6 | swift版本提供 10 个模式 7 | ``` 8 | public enum JWDatePickerMode:Int{ 9 | 10 | case dateAndTime// 年月日 时 分 秒 11 | case dateAndHour// 年月日 时 12 | case dateAndTimeRYear// 月日 时 分 秒 13 | case time// 时 分 秒 14 | case timeRSecond// 时 分 15 | case date// 年 月 日 16 | case dateAddHour// 年 月 日 时 17 | case dateAndTimeRSecond// 年月日 时 分 18 | case dateAndTimeRYearAndSecond// 月日 时 分 3 19 | case dateAndTimeForAllComponent// 年 月 日 时 分 秒 20 | } 21 | ``` 22 | 23 | OC版本主要提供8 个模式 24 | ``` 25 | JWDatePickerMode_DateAndTime,// 年月日 时 分 秒 26 | JWDatePickerMode_DateAndTimeRYear,// 月日 时 分 秒 27 | JWDatePickerMode_Time,// 时分秒 28 | JWDatePickerMode_TimeRSecond,//时分 29 | JWDatePickerMode_Date,// 年月日 30 | JWDatePickerMode_DateAddHour,// 年 月 日 时 31 | JWDatePickerMode_DateAndTimeRSecond,// 年月日 时 分 32 | JWDatePickerMode_DateAndTimeRYearAndSecond//月日 时 分 33 | ``` 34 | 35 | 36 | ====介绍:通过代理指定单位 37 | ``` 38 | -(NSString *)datePickerView:(JWDatePickerView *)datePickerView unitForCalendarUnit:(NSCalendarUnit)calendarUnit 39 | { 40 | 41 | switch (calendarUnit) { 42 | case NSCalendarUnitYear: 43 | return @"年"; 44 | break; 45 | case NSCalendarUnitMonth: 46 | return @"月"; 47 | break; 48 | case NSCalendarUnitDay: 49 | return @"日"; 50 | break; 51 | case NSCalendarUnitHour: 52 | return @"时"; 53 | break; 54 | case NSCalendarUnitMinute: 55 | return @"分"; 56 | break; 57 | case NSCalendarUnitSecond: 58 | return @"秒"; 59 | break; 60 | default: 61 | break; 62 | } 63 | return @" "; 64 | } 65 | ``` 66 | ====演示 67 |
68 | ![](https://github.com/GitHubOfJW/JWDatePickerView/blob/master/Source/PickerView.gif) 69 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | 日历控件 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /JWDatePickerView/JWDatePickerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JWDatePickerView.h 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | typedef NS_ENUM(NSUInteger,JWDatePickerMode) 13 | { 14 | JWDatePickerMode_DateAndTime,// 年月日 时 分 秒 4 15 | JWDatePickerMode_DateAndTimeRYear,// 月日 时 分 秒 4 16 | JWDatePickerMode_Time,// 时分秒 3 17 | JWDatePickerMode_TimeRSecond,//时分 2 18 | JWDatePickerMode_Date,// 年月日 3 19 | JWDatePickerMode_DateAddHour,// 年 月 日 时 4 20 | JWDatePickerMode_DateAndTimeRSecond,// 年月日 时 分 3 21 | JWDatePickerMode_DateAndTimeRYearAndSecond//月日 时 分 3 22 | }; 23 | 24 | @class JWDatePickerView; 25 | /** 26 | * 代理方法 27 | */ 28 | @protocol JWDatePickerViewDelegate 29 | 30 | /** 31 | * 返回单位文字 比如说 参数NSCalendarUnitYear 返回 年 例如 2016年 没有则返回@""或者nil 32 | */ 33 | -(NSString*)datePickerView:(JWDatePickerView*)datePickerView unitForCalendarUnit:(NSCalendarUnit)calendarUnit; 34 | 35 | @end 36 | 37 | @interface JWDatePickerView : UIView 38 | 39 | /** 40 | * delegate 41 | */ 42 | @property(nonatomic,weak)id delegate; 43 | 44 | /** 45 | * 最小日期 如果是 不显示年的模式下 自动将最大日期设置在 一年内 只显示时分秒的同理 46 | */ 47 | @property(nonatomic,strong)NSDate* minDate; 48 | 49 | /** 50 | * 当前日期 如果比最小日期小,设置最小日期为 date 51 | */ 52 | @property(nonatomic,strong)NSDate* date; 53 | 54 | /** 55 | * 最大日起 如果是 不显示年的模式下 自动将最小日期设置在 一年内 只显示时分秒的同理 56 | */ 57 | @property(nonatomic,strong)NSDate* maxDate; 58 | 59 | /** 60 | * pickerModel 61 | */ 62 | @property(nonatomic,assign)JWDatePickerMode pickerMode; 63 | 64 | 65 | /** 66 | * font 67 | */ 68 | @property(nonatomic,strong)UIFont* font; 69 | 70 | 71 | 72 | /** 73 | * minuteSpace 分钟间隔 条件 minuteSpace<30&&60%minuteSpace==0 74 | */ 75 | @property(nonatomic,assign)NSUInteger minuteSpace; 76 | 77 | /** 78 | * secondSpace 秒间隔 条件 secondSpace<30&&60%secondSpace==0 79 | */ 80 | @property(nonatomic,assign)NSUInteger secondSpace; 81 | 82 | /** 83 | * 刷新数据 84 | */ 85 | -(void)reloadData; 86 | 87 | 88 | /** 89 | * 四舍五入 date 数据 90 | */ 91 | -(NSDate*)getRoundDateWithDate:(NSDate*)date; 92 | 93 | /** 94 | * 获取一天中的 最小时间00:00:00 最大时间 23:59:59 95 | */ 96 | -(NSDate*)getDayLastDateWithDate:(NSDate*)date max:(BOOL)isGetMax; 97 | 98 | /** 99 | * 获取日期字符串 100 | */ 101 | -(NSString*)getDateStr; 102 | /** 103 | * 获取日期字符串 104 | */ 105 | -(NSString*)getDateStrWithDateFormatterString:(NSString*)formatterStr; 106 | @end 107 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/JWDatePickerView/JWDatePickerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JWDatePickerView.h 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | typedef NS_ENUM(NSUInteger,JWDatePickerMode) 13 | { 14 | JWDatePickerMode_DateAndTime,// 年月日 时 分 秒 4 15 | JWDatePickerMode_DateAndTimeRYear,// 月日 时 分 秒 4 16 | JWDatePickerMode_Time,// 时分秒 3 17 | JWDatePickerMode_TimeRSecond,//时分 2 18 | JWDatePickerMode_Date,// 年月日 3 19 | JWDatePickerMode_DateAddHour,// 年 月 日 时 4 20 | JWDatePickerMode_DateAndTimeRSecond,// 年月日 时 分 3 21 | JWDatePickerMode_DateAndTimeRYearAndSecond//月日 时 分 3 22 | }; 23 | 24 | @class JWDatePickerView; 25 | /** 26 | * 代理方法 27 | */ 28 | @protocol JWDatePickerViewDelegate 29 | 30 | /** 31 | * 返回单位文字 比如说 参数NSCalendarUnitYear 返回 年 例如 2016年 没有则返回@""或者nil 32 | */ 33 | -(NSString*)datePickerView:(JWDatePickerView*)datePickerView unitForCalendarUnit:(NSCalendarUnit)calendarUnit; 34 | 35 | @end 36 | 37 | @interface JWDatePickerView : UIView 38 | 39 | /** 40 | * delegate 41 | */ 42 | @property(nonatomic,weak)id delegate; 43 | 44 | /** 45 | * 最小日期 如果是 不显示年的模式下 自动将最大日期设置在 一年内 只显示时分秒的同理 46 | */ 47 | @property(nonatomic,strong)NSDate* minDate; 48 | 49 | /** 50 | * 当前日期 如果比最小日期小,设置最小日期为 date 51 | */ 52 | @property(nonatomic,strong)NSDate* date; 53 | 54 | /** 55 | * 最大日起 如果是 不显示年的模式下 自动将最小日期设置在 一年内 只显示时分秒的同理 56 | */ 57 | @property(nonatomic,strong)NSDate* maxDate; 58 | 59 | /** 60 | * pickerModel 61 | */ 62 | @property(nonatomic,assign)JWDatePickerMode pickerMode; 63 | 64 | 65 | /** 66 | * font 67 | */ 68 | @property(nonatomic,strong)UIFont* font; 69 | 70 | 71 | 72 | /** 73 | * minuteSpace 分钟间隔 条件 minuteSpace<30&&60%minuteSpace==0 74 | */ 75 | @property(nonatomic,assign)NSUInteger minuteSpace; 76 | 77 | /** 78 | * secondSpace 秒间隔 条件 secondSpace<30&&60%secondSpace==0 79 | */ 80 | @property(nonatomic,assign)NSUInteger secondSpace; 81 | 82 | /** 83 | * 刷新数据 84 | */ 85 | -(void)reloadData; 86 | 87 | 88 | /** 89 | * 四舍五入 date 数据 90 | */ 91 | -(NSDate*)getRoundDateWithDate:(NSDate*)date; 92 | 93 | /** 94 | * 获取一天中的 最小时间00:00:00 最大时间 23:59:59 95 | */ 96 | -(NSDate*)getDayLastDateWithDate:(NSDate*)date max:(BOOL)isGetMax; 97 | 98 | /** 99 | * 获取日期字符串 100 | */ 101 | -(NSString*)getDateStr; 102 | /** 103 | * 获取日期字符串 104 | */ 105 | -(NSString*)getDateStrWithDateFormatterString:(NSString*)formatterStr; 106 | @end 107 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView.xcodeproj/xcuserdata/zhujianwei.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 18 | 30 | 31 | 32 | 34 | 46 | 47 | 48 | 50 | 56 | 57 | 58 | 60 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView.xcodeproj/xcuserdata/zhujianwei.xcuserdatad/xcschemes/JWDatePickerView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | #import "KBDatePickerViewkeyBoard.h" 9 | #import "JWDatePickerView.h" 10 | #import "ViewController.h" 11 | 12 | @interface ViewController () 13 | /** 14 | * pickerView 15 | */ 16 | @property(nonatomic,strong)JWDatePickerView* pickerView; 17 | 18 | /** 19 | * textField 20 | */ 21 | @property(nonatomic,strong)UITextField* txtField; 22 | 23 | /** 24 | * kb 25 | */ 26 | @property(nonatomic,strong)KBDatePickerViewkeyBoard* keyboard; 27 | @end 28 | 29 | @implementation ViewController 30 | 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | 34 | self.navigationItem.title = @"日期键盘"; 35 | 36 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"切换模式" style:(UIBarButtonItemStyleDone) target:self action:@selector(change)]; 37 | 38 | [self.view addSubview:self.pickerView]; 39 | 40 | [self.view addSubview:self.txtField]; 41 | } 42 | 43 | -(void)change 44 | { 45 | if(self.pickerView.pickerMode () 14 | 15 | var didConfirmDateClosure:ConfirmDateClosure? 16 | 17 | 18 | var isRemove:Bool = false 19 | 20 | var font:UIFont?{ 21 | willSet{ 22 | if let f = font { 23 | titleLabel?.font = f 24 | titleLabel?.text = "日期选择" 25 | cancelBtn?.titleLabel?.font = f 26 | confirmBtn?.titleLabel?.font = f 27 | } 28 | } 29 | } 30 | 31 | 32 | var title:String?{ 33 | willSet{ 34 | if let t = newValue{ 35 | titleLabel?.text = t 36 | } 37 | } 38 | } 39 | 40 | //蒙版 41 | private var cover:UIControl = { 42 | let view:UIControl = UIControl(frame: ScreenBounds) 43 | view.backgroundColor = UIColor.black 44 | view.alpha = 0.4 45 | 46 | return view 47 | }() 48 | 49 | //取消按钮 50 | private var cancelBtn:UIButton? 51 | 52 | //确定按钮 53 | private var confirmBtn:UIButton? 54 | 55 | //头部标题 56 | private var titleLabel:UILabel? 57 | 58 | //头部View 59 | private var titleView:UIView? 60 | 61 | //pickerView 62 | let pickerView:JWDatePickerView = JWDatePickerView() 63 | 64 | override init(frame: CGRect) { 65 | super.init(frame: frame) 66 | 67 | backgroundColor = UIColor.white 68 | 69 | cover.addTarget(self, action: #selector(JWDatePickerKeyBoardView.exitKeyBoard), for: UIControlEvents.touchUpInside) 70 | 71 | // FontPrompt_120_218_317_416_515_614_712_810_908 72 | font = Font4 73 | 74 | //标题View 75 | titleView = UIView() 76 | titleView?.backgroundColor = UIColor.orange 77 | addSubview(titleView!) 78 | 79 | //取消按钮 80 | cancelBtn = UIButton() 81 | cancelBtn?.addTarget(self, action:#selector(JWDatePickerKeyBoardView.btnClick(btn:)), for: UIControlEvents.touchUpInside) 82 | cancelBtn?.titleLabel?.font = font 83 | cancelBtn?.setTitle("取消", for: UIControlState.normal) 84 | cancelBtn?.setTitle("取消", for: UIControlState.selected) 85 | cancelBtn?.setTitleColor(UIColor.white, for: UIControlState.normal) 86 | cancelBtn?.tag = 0 87 | titleView?.addSubview(cancelBtn!) 88 | 89 | //确定按钮 90 | confirmBtn = UIButton() 91 | confirmBtn?.addTarget(self, action:#selector(JWDatePickerKeyBoardView.btnClick(btn:)), for: UIControlEvents.touchUpInside) 92 | confirmBtn?.titleLabel?.font = font 93 | confirmBtn?.setTitle("确定", for: UIControlState.normal) 94 | confirmBtn?.setTitle("确定", for: UIControlState.selected) 95 | confirmBtn?.setTitleColor(UIColor.white, for: UIControlState.normal) 96 | confirmBtn?.tag = 1 97 | titleView?.addSubview(confirmBtn!) 98 | 99 | //标题 100 | titleLabel = UILabel() 101 | titleLabel?.textAlignment = NSTextAlignment.center 102 | titleLabel?.font = font 103 | titleLabel?.text = title 104 | titleLabel?.textColor = UIColor.white 105 | titleView?.addSubview(titleLabel!) 106 | 107 | //pickerView 108 | addSubview(pickerView) 109 | } 110 | 111 | 112 | internal func btnClick(btn:UIButton) { 113 | if btn.tag == 1 { 114 | if let closure = didConfirmDateClosure{ 115 | if let date = pickerView.date{ 116 | closure(date) 117 | } 118 | } 119 | } 120 | 121 | cover.alpha = 0.021; 122 | UIApplication.shared.keyWindow?.endEditing(true) 123 | 124 | } 125 | 126 | override func layoutSubviews() { 127 | super.layoutSubviews() 128 | 129 | //titleView 130 | setH(256) 131 | 132 | let titleViewX:CGFloat = 0 133 | let titleViewY:CGFloat = 0 134 | let titleViewW:CGFloat = bounds.width 135 | let titleViewH:CGFloat = 50 136 | titleView?.frame = CGRect(x: titleViewX, y: titleViewY, width: titleViewW, height: titleViewH) 137 | 138 | let cancelX:CGFloat = 0 139 | let cancelY:CGFloat = 0 140 | let cancelW:CGFloat = 80 141 | let cancelH:CGFloat = titleViewH 142 | cancelBtn?.frame = CGRect(x: cancelX, y: cancelY, width: cancelW, height: cancelH) 143 | 144 | let confirmW:CGFloat = cancelW 145 | let confirmH:CGFloat = titleViewH 146 | let confirmX:CGFloat = bounds.width - confirmW 147 | let confirmY:CGFloat = 0 148 | confirmBtn?.frame = CGRect(x: confirmX, y: confirmY, width: confirmW, height: confirmH) 149 | 150 | let titleW:CGFloat = bounds.width - cancelW*2 151 | let titleH:CGFloat = titleViewH 152 | let titleX:CGFloat = (cancelBtn?.frame.maxX)! 153 | let titleY:CGFloat = 0 154 | titleLabel?.frame = CGRect(x: titleX, y: titleY, width: titleW, height: titleH) 155 | 156 | 157 | let pickerX:CGFloat = 0 158 | let pickerY:CGFloat = titleViewH 159 | let pickerW:CGFloat = titleViewW 160 | let pickerH:CGFloat = bounds.size.height - titleViewH 161 | pickerView.frame = CGRect(x: pickerX, y: pickerY, width: pickerW, height: pickerH) 162 | 163 | } 164 | 165 | required init?(coder aDecoder: NSCoder) { 166 | fatalError("init(coder:) has not been implemented") 167 | } 168 | 169 | 170 | /** 171 | * 此方法当 自定键盘移动到窗口上调用 172 | */ 173 | override func didMoveToWindow() { 174 | super.didMoveToWindow() 175 | if isRemove == false { 176 | let window:UIWindow = UIApplication.shared.keyWindow! 177 | cover.frame = ScreenBounds 178 | cover.alpha = 0.4 179 | window.addSubview(cover) 180 | }else 181 | { 182 | isRemove = false 183 | } 184 | } 185 | 186 | 187 | /** 188 | * 移除时 将蒙板一并移除 189 | */ 190 | override func removeFromSuperview() { 191 | isRemove = true 192 | cover.removeFromSuperview() 193 | 194 | super.removeFromSuperview() 195 | } 196 | 197 | 198 | func exitKeyBoard() { 199 | cover.alpha = 0.021 200 | UIApplication.shared.keyWindow?.endEditing(true) 201 | } 202 | 203 | } 204 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/JWDatePickerView/KBDatePickerViewkeyBoard.m: -------------------------------------------------------------------------------- 1 | // 2 | // KBSexkeyBoard.m 3 | // SunCarGuide 4 | // 5 | // Created by 朱建伟 on 15/12/17. 6 | // Copyright © 2015年 jryghq. All rights reserved. 7 | // 8 | #import "KBDatePickerViewkeyBoard.h" 9 | @interface KBDatePickerViewkeyBoard() 10 | @property(nonatomic,strong)UIControl *cover; 11 | 12 | @property(nonatomic,strong)UIView *titleView; 13 | @property(nonatomic,strong)UILabel *titleLabel; 14 | @property(nonatomic,strong)UIButton *cancelBtn; 15 | @property(nonatomic,strong)UIButton *confirmBtn; 16 | 17 | 18 | @property(nonatomic,strong)NSString *currentTitle; 19 | 20 | @property(nonatomic,assign)BOOL isRemove; 21 | 22 | @property(nonatomic,assign)BOOL flag; 23 | 24 | 25 | @end 26 | 27 | @implementation KBDatePickerViewkeyBoard 28 | 29 | /** 30 | * 快捷初始化 31 | */ 32 | -(instancetype)initWithFrame:(CGRect)frame title:(NSString *)title currentDayName:(NSString *)currentDayName 33 | { 34 | if (self = [self initWithFrame:frame]) { 35 | self.title =title; 36 | self.titleLabel.text = title; 37 | self.currentTitle = currentDayName; 38 | } 39 | return self; 40 | } 41 | 42 | 43 | /** 44 | * 初始化 45 | */ 46 | -(instancetype)initWithFrame:(CGRect)frame 47 | { 48 | if(self = [super initWithFrame:frame]) 49 | { 50 | self.flag = YES; 51 | 52 | [self setClipsToBounds:NO]; 53 | 54 | _cover = [[UIControl alloc] init]; 55 | _cover.backgroundColor = [UIColor blackColor]; 56 | [_cover addTarget:self 57 | action:@selector(ExitKeyboard) forControlEvents:(UIControlEventTouchUpInside)]; 58 | _cover.alpha = 0.4; 59 | 60 | //标题View 61 | _titleView = [[UIView alloc] init]; 62 | [self addSubview:_titleView ]; 63 | 64 | //标题 65 | _titleLabel =[[UILabel alloc] init]; 66 | _titleLabel.text = @"请选择"; 67 | // CGFloat titleValue = 160; 68 | _titleLabel.textColor = [UIColor orangeColor];//[UIColor colorWithRed:(titleValue/255.0) green:(titleValue/255.0) blue:(titleValue/255.0) alpha:1]; 69 | _titleLabel.textAlignment = NSTextAlignmentCenter; 70 | _titleLabel.font = [UIFont systemFontOfSize:16]; 71 | [_titleView addSubview:_titleLabel]; 72 | 73 | //取消 74 | _cancelBtn = [[UIButton alloc] init]; 75 | [_cancelBtn setTitleColor:[UIColor orangeColor]forState:(UIControlStateNormal)]; 76 | [_cancelBtn setTitle:NSLocalizedString(@"取消",nil) forState:(UIControlStateNormal)]; 77 | _cancelBtn.titleLabel.font =[UIFont systemFontOfSize:16]; 78 | _cancelBtn.tag = 0; 79 | [_cancelBtn addTarget:self 80 | action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 81 | [_titleView addSubview:_cancelBtn]; 82 | 83 | //确定 84 | _confirmBtn = [[UIButton alloc] init]; 85 | [_confirmBtn setTitleColor:[UIColor orangeColor]forState:(UIControlStateNormal)]; 86 | [_confirmBtn setTitle:NSLocalizedString(@"确定",nil) forState:(UIControlStateNormal)]; 87 | _confirmBtn.titleLabel.font =[UIFont systemFontOfSize:16]; 88 | _confirmBtn.tag = 1; 89 | [_confirmBtn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 90 | [_titleView addSubview:_confirmBtn]; 91 | 92 | 93 | //pickerView 94 | _pickerView =[[JWDatePickerView alloc] init]; 95 | _pickerView.backgroundColor = [UIColor whiteColor]; 96 | [self addSubview:_pickerView]; 97 | 98 | } 99 | return self; 100 | } 101 | 102 | 103 | -(void)layoutSubviews 104 | { 105 | [super layoutSubviews]; 106 | 107 | CGFloat width = self.bounds.size.width; 108 | CGFloat height = 216; 109 | CGFloat margin = 10; 110 | 111 | CGFloat btnW = 80; 112 | 113 | CGFloat titleViewW = width; 114 | CGFloat titleViewH = 44; 115 | CGFloat titleViewX =0; 116 | CGFloat titleViewY =0; 117 | self.titleView.frame = CGRectMake(titleViewX, titleViewY, titleViewW, titleViewH); 118 | 119 | CGFloat cancelBtnW =btnW; 120 | CGFloat cancelBtnH = titleViewH; 121 | CGFloat cancelBtnX = margin; 122 | CGFloat cancelBtnY = 0; 123 | self.cancelBtn.frame =CGRectMake(cancelBtnX, cancelBtnY, cancelBtnW, cancelBtnH); 124 | 125 | 126 | CGFloat confirmBtnW = btnW; 127 | CGFloat confirmBtnH = titleViewH; 128 | CGFloat confirmBtnX = width - margin - confirmBtnW; 129 | CGFloat confirmBtnY = 0; 130 | self.confirmBtn.frame =CGRectMake(confirmBtnX, confirmBtnY, confirmBtnW, confirmBtnH); 131 | 132 | 133 | CGFloat titleLabelH = titleViewH; 134 | CGFloat titleLabelX = (cancelBtnX+cancelBtnW); 135 | CGFloat titleLabelW = confirmBtnX - titleLabelX; 136 | CGFloat titleLabelY = 0; 137 | self.titleLabel.frame = CGRectMake(titleLabelX, titleLabelY, titleLabelW, titleLabelH); 138 | 139 | 140 | CGFloat pickerViewX = 0; 141 | CGFloat pickerViewY = titleViewH; 142 | CGFloat pickerViewW = width; 143 | CGFloat pickerViewH = height - pickerViewY+margin; 144 | self.pickerView.frame = CGRectMake(pickerViewX, pickerViewY, pickerViewW, pickerViewH); 145 | 146 | } 147 | 148 | 149 | -(void)setTitle:(NSString *)title 150 | { 151 | _title = title; 152 | 153 | self.titleLabel.text = title; 154 | 155 | } 156 | 157 | 158 | /** 159 | * 此方法当 自定键盘移动到窗口上调用 160 | */ 161 | -(void)didMoveToWindow 162 | { 163 | [super didMoveToWindow]; 164 | if (!self.isRemove) { 165 | UIWindow *window = [UIApplication sharedApplication].keyWindow; 166 | self.cover.frame = CGRectMake(0,0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height); 167 | self.cover.alpha = 0.4; 168 | [window addSubview:self.cover]; 169 | }else 170 | { 171 | self.isRemove = NO; 172 | } 173 | } 174 | 175 | 176 | 177 | /** 178 | * 移除时 将蒙板一并移除 179 | */ 180 | -(void)removeFromSuperview 181 | { 182 | self.isRemove = YES; 183 | [self.cover removeFromSuperview]; 184 | [super removeFromSuperview]; 185 | } 186 | 187 | 188 | -(void)btnClick:(UIButton*)btn 189 | { 190 | if (btn.tag) {//确定 191 | if (self.didSelectedBlock&&self.pickerView.date) { 192 | self.didSelectedBlock(self.pickerView.date,[self.pickerView getDateStr]); 193 | } 194 | } 195 | 196 | self.cover.alpha = 0.021; 197 | 198 | [[UIApplication sharedApplication].keyWindow endEditing:YES]; 199 | } 200 | 201 | 202 | -(void)ExitKeyboard{ 203 | self.cover.alpha = 0.021; 204 | [[UIApplication sharedApplication].keyWindow endEditing:YES]; 205 | } 206 | 207 | @end 208 | -------------------------------------------------------------------------------- /JWDatePickerView-Swift/JWPickerKeyBoardView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JWDatePickerKeyBoardView.swift 3 | // CarServer 4 | // 5 | // Created by 朱建伟 on 2016/10/17. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class JWPickerKeyBoardView: UIView ,UIPickerViewDelegate,UIPickerViewDataSource{ 12 | 13 | typealias ConfirmDateClosure = (Int) -> () 14 | 15 | var didConfirmClosure:ConfirmDateClosure? 16 | 17 | var numberClosure:(()->Int)? 18 | 19 | var titleClosure:((Int)->String)? 20 | 21 | var isRemove:Bool = false 22 | 23 | var font:UIFont?{ 24 | willSet{ 25 | if let f = font { 26 | titleLabel?.font = f 27 | titleLabel?.text = "日期选择" 28 | cancelBtn?.titleLabel?.font = f 29 | confirmBtn?.titleLabel?.font = f 30 | } 31 | } 32 | } 33 | 34 | 35 | var title:String?{ 36 | willSet{ 37 | if let t = newValue{ 38 | titleLabel?.text = t 39 | } 40 | } 41 | } 42 | 43 | //蒙版 44 | private var cover:UIControl = { 45 | let view:UIControl = UIControl(frame: ScreenBounds) 46 | view.backgroundColor = UIColor.black 47 | view.alpha = 0.4 48 | 49 | return view 50 | }() 51 | 52 | //取消按钮 53 | private var cancelBtn:UIButton? 54 | 55 | //确定按钮 56 | private var confirmBtn:UIButton? 57 | 58 | //头部标题 59 | private var titleLabel:UILabel? 60 | 61 | //头部View 62 | private var titleView:UIView? 63 | 64 | //pickerView 65 | let pickerView:UIPickerView = UIPickerView() 66 | 67 | override init(frame: CGRect) { 68 | super.init(frame: frame) 69 | 70 | backgroundColor = UIColor.white 71 | 72 | pickerView.delegate = self 73 | pickerView.dataSource = self 74 | 75 | cover.addTarget(self, action: #selector(JWDatePickerKeyBoardView.exitKeyBoard), for: UIControlEvents.touchUpInside) 76 | 77 | // FontPrompt_120_218_317_416_515_614_712_810_908 78 | font = Font4 79 | 80 | //标题View 81 | titleView = UIView() 82 | let rgb:CGFloat = 220/255.0 83 | titleView?.backgroundColor = UIColor(red: rgb, green: rgb, blue: rgb, alpha: 1) 84 | addSubview(titleView!) 85 | 86 | //取消按钮 87 | cancelBtn = UIButton() 88 | cancelBtn?.addTarget(self, action:#selector(JWDatePickerKeyBoardView.btnClick(btn:)), for: UIControlEvents.touchUpInside) 89 | cancelBtn?.titleLabel?.font = font 90 | cancelBtn?.setTitle("取消", for: UIControlState.normal) 91 | cancelBtn?.setTitle("取消", for: UIControlState.selected) 92 | cancelBtn?.setTitleColor(UIColor.orange, for: UIControlState.normal) 93 | cancelBtn?.tag = 0 94 | titleView?.addSubview(cancelBtn!) 95 | 96 | //确定按钮 97 | confirmBtn = UIButton() 98 | confirmBtn?.addTarget(self, action:#selector(JWDatePickerKeyBoardView.btnClick(btn:)), for: UIControlEvents.touchUpInside) 99 | confirmBtn?.titleLabel?.font = font 100 | confirmBtn?.setTitle("确定", for: UIControlState.normal) 101 | confirmBtn?.setTitle("确定", for: UIControlState.selected) 102 | confirmBtn?.setTitleColor(UIColor.orange, for: UIControlState.normal) 103 | confirmBtn?.tag = 1 104 | titleView?.addSubview(confirmBtn!) 105 | 106 | //标题 107 | titleLabel = UILabel() 108 | titleLabel?.textAlignment = NSTextAlignment.center 109 | titleLabel?.font = font 110 | titleLabel?.text = title 111 | titleLabel?.textColor = FontGrayColor 112 | titleView?.addSubview(titleLabel!) 113 | 114 | //pickerView 115 | addSubview(pickerView) 116 | } 117 | 118 | 119 | func numberOfComponents(in pickerView: UIPickerView) -> Int { 120 | return 1 121 | } 122 | 123 | 124 | 125 | func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 126 | if let closure = self.numberClosure{ 127 | if self.titleClosure != nil{ 128 | return closure() 129 | } 130 | } 131 | 132 | return 0 133 | 134 | } 135 | 136 | //返回选项高度 137 | internal func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { 138 | return pickerView.bounds.height/5 139 | } 140 | 141 | 142 | //返回label 143 | internal func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { 144 | 145 | let title:String = titleClosure!(row) 146 | 147 | var label:UILabel? = nil 148 | 149 | if view != nil { 150 | label = view as! UILabel? 151 | }else{ 152 | label = UILabel() 153 | label?.textAlignment = NSTextAlignment.center 154 | label?.textColor = FontGrayColor 155 | // Font_120_218_317_416_515_614_712_810_908 156 | label?.font = Font4 157 | label?.text = title 158 | } 159 | return label! 160 | } 161 | 162 | private var currentIndex:Int = 0 163 | func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 164 | currentIndex = row 165 | } 166 | 167 | 168 | internal func btnClick(btn:UIButton) { 169 | if btn.tag == 1 { 170 | if let closure = didConfirmClosure{ 171 | closure(self.currentIndex) 172 | } 173 | } 174 | 175 | cover.alpha = 0.021; 176 | UIApplication.shared.keyWindow?.endEditing(true) 177 | 178 | } 179 | 180 | override func layoutSubviews() { 181 | super.layoutSubviews() 182 | 183 | //titleView 184 | setH(256) 185 | 186 | let titleViewX:CGFloat = 0 187 | let titleViewY:CGFloat = 0 188 | let titleViewW:CGFloat = bounds.width 189 | let titleViewH:CGFloat = 50 190 | titleView?.frame = CGRect(x: titleViewX, y: titleViewY, width: titleViewW, height: titleViewH) 191 | 192 | let cancelX:CGFloat = 0 193 | let cancelY:CGFloat = 0 194 | let cancelW:CGFloat = 80 195 | let cancelH:CGFloat = titleViewH 196 | cancelBtn?.frame = CGRect(x: cancelX, y: cancelY, width: cancelW, height: cancelH) 197 | 198 | let confirmW:CGFloat = cancelW 199 | let confirmH:CGFloat = titleViewH 200 | let confirmX:CGFloat = bounds.width - confirmW 201 | let confirmY:CGFloat = 0 202 | confirmBtn?.frame = CGRect(x: confirmX, y: confirmY, width: confirmW, height: confirmH) 203 | 204 | let titleW:CGFloat = bounds.width - cancelW*2 205 | let titleH:CGFloat = titleViewH 206 | let titleX:CGFloat = (cancelBtn?.frame.maxX)! 207 | let titleY:CGFloat = 0 208 | titleLabel?.frame = CGRect(x: titleX, y: titleY, width: titleW, height: titleH) 209 | 210 | 211 | let pickerX:CGFloat = 0 212 | let pickerY:CGFloat = titleViewH 213 | let pickerW:CGFloat = titleViewW 214 | let pickerH:CGFloat = bounds.size.height - titleViewH 215 | pickerView.frame = CGRect(x: pickerX, y: pickerY, width: pickerW, height: pickerH) 216 | 217 | } 218 | 219 | required init?(coder aDecoder: NSCoder) { 220 | fatalError("init(coder:) has not been implemented") 221 | } 222 | 223 | 224 | /** 225 | * 此方法当 自定键盘移动到窗口上调用 226 | */ 227 | override func didMoveToWindow() { 228 | super.didMoveToWindow() 229 | if isRemove == false { 230 | let window:UIWindow = UIApplication.shared.keyWindow! 231 | cover.frame = ScreenBounds 232 | cover.alpha = 0.4 233 | window.addSubview(cover) 234 | }else 235 | { 236 | isRemove = false 237 | } 238 | } 239 | 240 | 241 | /** 242 | * 移除时 将蒙板一并移除 243 | */ 244 | override func removeFromSuperview() { 245 | isRemove = true 246 | cover.removeFromSuperview() 247 | 248 | super.removeFromSuperview() 249 | } 250 | 251 | 252 | func exitKeyBoard() { 253 | cover.alpha = 0.021 254 | UIApplication.shared.keyWindow?.endEditing(true) 255 | } 256 | 257 | func reloadData() { 258 | self.currentIndex = 0 259 | pickerView.reloadAllComponents() 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5BA28ADF1D3DC2F300E4AFEA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BA28ADE1D3DC2F300E4AFEA /* main.m */; }; 11 | 5BA28AE21D3DC2F300E4AFEA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BA28AE11D3DC2F300E4AFEA /* AppDelegate.m */; }; 12 | 5BA28AE51D3DC2F300E4AFEA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BA28AE41D3DC2F300E4AFEA /* ViewController.m */; }; 13 | 5BA28AE81D3DC2F300E4AFEA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5BA28AE61D3DC2F300E4AFEA /* Main.storyboard */; }; 14 | 5BA28AEB1D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5BA28AE91D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodeld */; }; 15 | 5BA28AED1D3DC2F300E4AFEA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5BA28AEC1D3DC2F300E4AFEA /* Assets.xcassets */; }; 16 | 5BA28AF01D3DC2F300E4AFEA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5BA28AEE1D3DC2F300E4AFEA /* LaunchScreen.storyboard */; }; 17 | 5BA28AFA1D3DC32A00E4AFEA /* JWDatePickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BA28AF91D3DC32A00E4AFEA /* JWDatePickerView.m */; }; 18 | 5BA28AFD1D3E10EE00E4AFEA /* KBDatePickerViewkeyBoard.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BA28AFC1D3E10EE00E4AFEA /* KBDatePickerViewkeyBoard.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 5BA28ADA1D3DC2F300E4AFEA /* JWDatePickerView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JWDatePickerView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 5BA28ADE1D3DC2F300E4AFEA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 24 | 5BA28AE01D3DC2F300E4AFEA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 25 | 5BA28AE11D3DC2F300E4AFEA /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 26 | 5BA28AE31D3DC2F300E4AFEA /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 27 | 5BA28AE41D3DC2F300E4AFEA /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 28 | 5BA28AE71D3DC2F300E4AFEA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 5BA28AEA1D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = JWDatePickerView.xcdatamodel; sourceTree = ""; }; 30 | 5BA28AEC1D3DC2F300E4AFEA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | 5BA28AEF1D3DC2F300E4AFEA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | 5BA28AF11D3DC2F300E4AFEA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | 5BA28AF81D3DC32A00E4AFEA /* JWDatePickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWDatePickerView.h; sourceTree = ""; }; 34 | 5BA28AF91D3DC32A00E4AFEA /* JWDatePickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWDatePickerView.m; sourceTree = ""; }; 35 | 5BA28AFB1D3E10ED00E4AFEA /* KBDatePickerViewkeyBoard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KBDatePickerViewkeyBoard.h; sourceTree = ""; }; 36 | 5BA28AFC1D3E10EE00E4AFEA /* KBDatePickerViewkeyBoard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KBDatePickerViewkeyBoard.m; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 5BA28AD71D3DC2F300E4AFEA /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | 5BA28AD11D3DC2F300E4AFEA = { 51 | isa = PBXGroup; 52 | children = ( 53 | 5BA28ADC1D3DC2F300E4AFEA /* JWDatePickerView */, 54 | 5BA28ADB1D3DC2F300E4AFEA /* Products */, 55 | ); 56 | sourceTree = ""; 57 | }; 58 | 5BA28ADB1D3DC2F300E4AFEA /* Products */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 5BA28ADA1D3DC2F300E4AFEA /* JWDatePickerView.app */, 62 | ); 63 | name = Products; 64 | sourceTree = ""; 65 | }; 66 | 5BA28ADC1D3DC2F300E4AFEA /* JWDatePickerView */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 5BA28AF71D3DC2FA00E4AFEA /* JWDatePickerView */, 70 | 5BA28AE01D3DC2F300E4AFEA /* AppDelegate.h */, 71 | 5BA28AE11D3DC2F300E4AFEA /* AppDelegate.m */, 72 | 5BA28AE31D3DC2F300E4AFEA /* ViewController.h */, 73 | 5BA28AE41D3DC2F300E4AFEA /* ViewController.m */, 74 | 5BA28AE61D3DC2F300E4AFEA /* Main.storyboard */, 75 | 5BA28AEC1D3DC2F300E4AFEA /* Assets.xcassets */, 76 | 5BA28AEE1D3DC2F300E4AFEA /* LaunchScreen.storyboard */, 77 | 5BA28AF11D3DC2F300E4AFEA /* Info.plist */, 78 | 5BA28AE91D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodeld */, 79 | 5BA28ADD1D3DC2F300E4AFEA /* Supporting Files */, 80 | ); 81 | path = JWDatePickerView; 82 | sourceTree = ""; 83 | }; 84 | 5BA28ADD1D3DC2F300E4AFEA /* Supporting Files */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 5BA28ADE1D3DC2F300E4AFEA /* main.m */, 88 | ); 89 | name = "Supporting Files"; 90 | sourceTree = ""; 91 | }; 92 | 5BA28AF71D3DC2FA00E4AFEA /* JWDatePickerView */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 5BA28AFB1D3E10ED00E4AFEA /* KBDatePickerViewkeyBoard.h */, 96 | 5BA28AFC1D3E10EE00E4AFEA /* KBDatePickerViewkeyBoard.m */, 97 | 5BA28AF81D3DC32A00E4AFEA /* JWDatePickerView.h */, 98 | 5BA28AF91D3DC32A00E4AFEA /* JWDatePickerView.m */, 99 | ); 100 | path = JWDatePickerView; 101 | sourceTree = ""; 102 | }; 103 | /* End PBXGroup section */ 104 | 105 | /* Begin PBXNativeTarget section */ 106 | 5BA28AD91D3DC2F300E4AFEA /* JWDatePickerView */ = { 107 | isa = PBXNativeTarget; 108 | buildConfigurationList = 5BA28AF41D3DC2F300E4AFEA /* Build configuration list for PBXNativeTarget "JWDatePickerView" */; 109 | buildPhases = ( 110 | 5BA28AD61D3DC2F300E4AFEA /* Sources */, 111 | 5BA28AD71D3DC2F300E4AFEA /* Frameworks */, 112 | 5BA28AD81D3DC2F300E4AFEA /* Resources */, 113 | ); 114 | buildRules = ( 115 | ); 116 | dependencies = ( 117 | ); 118 | name = JWDatePickerView; 119 | productName = JWDatePickerView; 120 | productReference = 5BA28ADA1D3DC2F300E4AFEA /* JWDatePickerView.app */; 121 | productType = "com.apple.product-type.application"; 122 | }; 123 | /* End PBXNativeTarget section */ 124 | 125 | /* Begin PBXProject section */ 126 | 5BA28AD21D3DC2F300E4AFEA /* Project object */ = { 127 | isa = PBXProject; 128 | attributes = { 129 | LastUpgradeCheck = 0730; 130 | ORGANIZATIONNAME = zhujianwei; 131 | TargetAttributes = { 132 | 5BA28AD91D3DC2F300E4AFEA = { 133 | CreatedOnToolsVersion = 7.3.1; 134 | DevelopmentTeam = 4575Y5U33P; 135 | }; 136 | }; 137 | }; 138 | buildConfigurationList = 5BA28AD51D3DC2F300E4AFEA /* Build configuration list for PBXProject "JWDatePickerView" */; 139 | compatibilityVersion = "Xcode 3.2"; 140 | developmentRegion = English; 141 | hasScannedForEncodings = 0; 142 | knownRegions = ( 143 | en, 144 | Base, 145 | ); 146 | mainGroup = 5BA28AD11D3DC2F300E4AFEA; 147 | productRefGroup = 5BA28ADB1D3DC2F300E4AFEA /* Products */; 148 | projectDirPath = ""; 149 | projectRoot = ""; 150 | targets = ( 151 | 5BA28AD91D3DC2F300E4AFEA /* JWDatePickerView */, 152 | ); 153 | }; 154 | /* End PBXProject section */ 155 | 156 | /* Begin PBXResourcesBuildPhase section */ 157 | 5BA28AD81D3DC2F300E4AFEA /* Resources */ = { 158 | isa = PBXResourcesBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | 5BA28AF01D3DC2F300E4AFEA /* LaunchScreen.storyboard in Resources */, 162 | 5BA28AED1D3DC2F300E4AFEA /* Assets.xcassets in Resources */, 163 | 5BA28AE81D3DC2F300E4AFEA /* Main.storyboard in Resources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXResourcesBuildPhase section */ 168 | 169 | /* Begin PBXSourcesBuildPhase section */ 170 | 5BA28AD61D3DC2F300E4AFEA /* Sources */ = { 171 | isa = PBXSourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | 5BA28AE51D3DC2F300E4AFEA /* ViewController.m in Sources */, 175 | 5BA28AFA1D3DC32A00E4AFEA /* JWDatePickerView.m in Sources */, 176 | 5BA28AEB1D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodeld in Sources */, 177 | 5BA28AE21D3DC2F300E4AFEA /* AppDelegate.m in Sources */, 178 | 5BA28AFD1D3E10EE00E4AFEA /* KBDatePickerViewkeyBoard.m in Sources */, 179 | 5BA28ADF1D3DC2F300E4AFEA /* main.m in Sources */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXSourcesBuildPhase section */ 184 | 185 | /* Begin PBXVariantGroup section */ 186 | 5BA28AE61D3DC2F300E4AFEA /* Main.storyboard */ = { 187 | isa = PBXVariantGroup; 188 | children = ( 189 | 5BA28AE71D3DC2F300E4AFEA /* Base */, 190 | ); 191 | name = Main.storyboard; 192 | sourceTree = ""; 193 | }; 194 | 5BA28AEE1D3DC2F300E4AFEA /* LaunchScreen.storyboard */ = { 195 | isa = PBXVariantGroup; 196 | children = ( 197 | 5BA28AEF1D3DC2F300E4AFEA /* Base */, 198 | ); 199 | name = LaunchScreen.storyboard; 200 | sourceTree = ""; 201 | }; 202 | /* End PBXVariantGroup section */ 203 | 204 | /* Begin XCBuildConfiguration section */ 205 | 5BA28AF21D3DC2F300E4AFEA /* Debug */ = { 206 | isa = XCBuildConfiguration; 207 | buildSettings = { 208 | ALWAYS_SEARCH_USER_PATHS = NO; 209 | CLANG_ANALYZER_NONNULL = YES; 210 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 211 | CLANG_CXX_LIBRARY = "libc++"; 212 | CLANG_ENABLE_MODULES = YES; 213 | CLANG_ENABLE_OBJC_ARC = YES; 214 | CLANG_WARN_BOOL_CONVERSION = YES; 215 | CLANG_WARN_CONSTANT_CONVERSION = YES; 216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 217 | CLANG_WARN_EMPTY_BODY = YES; 218 | CLANG_WARN_ENUM_CONVERSION = YES; 219 | CLANG_WARN_INT_CONVERSION = YES; 220 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 221 | CLANG_WARN_UNREACHABLE_CODE = YES; 222 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 223 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 224 | COPY_PHASE_STRIP = NO; 225 | DEBUG_INFORMATION_FORMAT = dwarf; 226 | ENABLE_STRICT_OBJC_MSGSEND = YES; 227 | ENABLE_TESTABILITY = YES; 228 | GCC_C_LANGUAGE_STANDARD = gnu99; 229 | GCC_DYNAMIC_NO_PIC = NO; 230 | GCC_NO_COMMON_BLOCKS = YES; 231 | GCC_OPTIMIZATION_LEVEL = 0; 232 | GCC_PREPROCESSOR_DEFINITIONS = ( 233 | "DEBUG=1", 234 | "$(inherited)", 235 | ); 236 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 237 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 238 | GCC_WARN_UNDECLARED_SELECTOR = YES; 239 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 240 | GCC_WARN_UNUSED_FUNCTION = YES; 241 | GCC_WARN_UNUSED_VARIABLE = YES; 242 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 243 | MTL_ENABLE_DEBUG_INFO = YES; 244 | ONLY_ACTIVE_ARCH = YES; 245 | SDKROOT = iphoneos; 246 | TARGETED_DEVICE_FAMILY = "1,2"; 247 | }; 248 | name = Debug; 249 | }; 250 | 5BA28AF31D3DC2F300E4AFEA /* Release */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_ANALYZER_NONNULL = YES; 255 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 256 | CLANG_CXX_LIBRARY = "libc++"; 257 | CLANG_ENABLE_MODULES = YES; 258 | CLANG_ENABLE_OBJC_ARC = YES; 259 | CLANG_WARN_BOOL_CONVERSION = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_EMPTY_BODY = YES; 263 | CLANG_WARN_ENUM_CONVERSION = YES; 264 | CLANG_WARN_INT_CONVERSION = YES; 265 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 269 | COPY_PHASE_STRIP = NO; 270 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 271 | ENABLE_NS_ASSERTIONS = NO; 272 | ENABLE_STRICT_OBJC_MSGSEND = YES; 273 | GCC_C_LANGUAGE_STANDARD = gnu99; 274 | GCC_NO_COMMON_BLOCKS = YES; 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 282 | MTL_ENABLE_DEBUG_INFO = NO; 283 | SDKROOT = iphoneos; 284 | TARGETED_DEVICE_FAMILY = "1,2"; 285 | VALIDATE_PRODUCT = YES; 286 | }; 287 | name = Release; 288 | }; 289 | 5BA28AF51D3DC2F300E4AFEA /* Debug */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 293 | CODE_SIGN_IDENTITY = "iPhone Developer"; 294 | INFOPLIST_FILE = JWDatePickerView/Info.plist; 295 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 296 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 297 | PRODUCT_BUNDLE_IDENTIFIER = com.zjw.otherApp; 298 | PRODUCT_NAME = "$(TARGET_NAME)"; 299 | }; 300 | name = Debug; 301 | }; 302 | 5BA28AF61D3DC2F300E4AFEA /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 306 | CODE_SIGN_IDENTITY = "iPhone Developer"; 307 | INFOPLIST_FILE = JWDatePickerView/Info.plist; 308 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 309 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 310 | PRODUCT_BUNDLE_IDENTIFIER = com.zjw.otherApp; 311 | PRODUCT_NAME = "$(TARGET_NAME)"; 312 | }; 313 | name = Release; 314 | }; 315 | /* End XCBuildConfiguration section */ 316 | 317 | /* Begin XCConfigurationList section */ 318 | 5BA28AD51D3DC2F300E4AFEA /* Build configuration list for PBXProject "JWDatePickerView" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | 5BA28AF21D3DC2F300E4AFEA /* Debug */, 322 | 5BA28AF31D3DC2F300E4AFEA /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | 5BA28AF41D3DC2F300E4AFEA /* Build configuration list for PBXNativeTarget "JWDatePickerView" */ = { 328 | isa = XCConfigurationList; 329 | buildConfigurations = ( 330 | 5BA28AF51D3DC2F300E4AFEA /* Debug */, 331 | 5BA28AF61D3DC2F300E4AFEA /* Release */, 332 | ); 333 | defaultConfigurationIsVisible = 0; 334 | defaultConfigurationName = Release; 335 | }; 336 | /* End XCConfigurationList section */ 337 | 338 | /* Begin XCVersionGroup section */ 339 | 5BA28AE91D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodeld */ = { 340 | isa = XCVersionGroup; 341 | children = ( 342 | 5BA28AEA1D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodel */, 343 | ); 344 | currentVersion = 5BA28AEA1D3DC2F300E4AFEA /* JWDatePickerView.xcdatamodel */; 345 | path = JWDatePickerView.xcdatamodeld; 346 | sourceTree = ""; 347 | versionGroupType = wrapper.xcdatamodel; 348 | }; 349 | /* End XCVersionGroup section */ 350 | }; 351 | rootObject = 5BA28AD21D3DC2F300E4AFEA /* Project object */; 352 | } 353 | -------------------------------------------------------------------------------- /JWDatePickerView/JWDatePickerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JWDatePickerView.m 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | #define KSplit @"(#拆#)"//用来拆分 9 | 10 | #define KTotalFormatter @"yyyy MM dd HH mm ss" 11 | #define KTotalFormatterStr @"%@ %@ %@ %@ %@ %@" 12 | 13 | #define KComUnit NSCalendarUnitYear|NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond 14 | 15 | 16 | #import "JWDatePickerView.h" 17 | 18 | @interface JWDatePickerView() 19 | /** 20 | * bgView 21 | */ 22 | @property(nonatomic,strong)UIView* bgView; 23 | /** 24 | * pickerView 25 | */ 26 | @property(nonatomic,strong)UIPickerView* pickerView; 27 | 28 | /** 29 | * modeDict 30 | */ 31 | @property(nonatomic,strong)NSMutableDictionary* modeDict; 32 | /** 33 | * formatterDict 34 | */ 35 | @property(nonatomic,strong)NSMutableDictionary* formatterDict; 36 | 37 | /** 38 | * unitdict 39 | */ 40 | @property(nonatomic,strong)NSMutableDictionary* unitStrDict; 41 | 42 | /** 43 | * calendar 44 | */ 45 | @property(nonatomic,strong)NSCalendar* calendar; 46 | 47 | /** 48 | * dateFormmater 49 | */ 50 | @property(nonatomic,strong)NSDateFormatter* dateF; 51 | 52 | 53 | /** 54 | * formmater 55 | */ 56 | @property(nonatomic,strong)NSDateFormatter* simpleDateF; 57 | 58 | /** 59 | * tempComps 60 | */ 61 | @property(nonatomic,strong)NSDateComponents *tempDateComps; 62 | 63 | 64 | @end 65 | 66 | @implementation JWDatePickerView 67 | 68 | /** 69 | * 初始化控件 70 | */ 71 | -(instancetype)initWithFrame:(CGRect)frame 72 | { 73 | if (self = [super initWithFrame:frame]) { 74 | self.minuteSpace = 1; 75 | self.secondSpace = 1; 76 | 77 | self.bgView = [[UIView alloc] init]; 78 | [self addSubview:self.bgView]; 79 | 80 | //模式 81 | self.pickerMode = JWDatePickerMode_DateAddHour; 82 | self.font = [UIFont boldSystemFontOfSize:16]; 83 | 84 | //pickerView 85 | self.pickerView = [[UIPickerView alloc] init]; 86 | self.pickerView.backgroundColor = [UIColor whiteColor]; 87 | self.pickerView.delegate = self; 88 | self.pickerView.dataSource = self; 89 | [self.bgView addSubview:self.pickerView]; 90 | 91 | } 92 | return self; 93 | } 94 | 95 | 96 | - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView 97 | { 98 | //返回对应模式下的compsCount 99 | // if (self.pickerMode==JWDatePickerMode_DateAndTime||self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAddHour) { 100 | // return 4; 101 | // }else if (self.pickerMode==JWDatePickerMode_TimeRSecond) 102 | // { 103 | // return 2; 104 | // } 105 | // return 3; 106 | return [self.modeDict objectForKey:@(self.pickerMode)].count; 107 | } 108 | 109 | 110 | - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component 111 | { 112 | NSArray* groupUnitArray = self.modeDict[@(self.pickerMode)]; 113 | if (component>=groupUnitArray.count) { 114 | return 0; 115 | } 116 | NSNumber* number = [groupUnitArray[component] lastObject]; 117 | 118 | switch (number.unsignedIntegerValue) { 119 | case NSCalendarUnitYear: 120 | { 121 | NSInteger year= [self.calendar component:number.unsignedIntegerValue fromDate:[self getMaxDate]]-[self.calendar component:number.unsignedIntegerValue fromDate:[self getMinDate]]+1; 122 | 123 | 124 | return year; 125 | break; 126 | } 127 | case NSCalendarUnitMonth: 128 | return 12; 129 | break; 130 | case NSCalendarUnitDay: 131 | { 132 | if (self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour) {//这个模式下 年 月 日 或者 年 月 日 时 133 | //根据年月日刷新 天数 134 | NSInteger days =[self getMonthDaysWithYear:self.tempDateComps.year andMoth:self.tempDateComps.month]; 135 | return days; 136 | }else 137 | { 138 | 139 | return [self.calendar components:number.unsignedIntegerValue fromDate:[self getMinDate] toDate:[self getMaxDate] options:NSCalendarMatchLast].day+1; 140 | } 141 | break; 142 | } 143 | case NSCalendarUnitHour: 144 | return 24; 145 | break; 146 | 147 | case NSCalendarUnitMinute: 148 | return 60/self.minuteSpace; 149 | break; 150 | 151 | case NSCalendarUnitSecond: 152 | return 60/self.secondSpace; 153 | break; 154 | default: 155 | break; 156 | } 157 | 158 | return 1; 159 | } 160 | 161 | 162 | 163 | -(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component 164 | { 165 | 166 | 167 | NSArray* groupUnitArray = self.modeDict[@(self.pickerMode)]; 168 | 169 | if (component>=groupUnitArray.count) { 170 | return @""; 171 | } 172 | NSNumber* number = [groupUnitArray[component] lastObject]; 173 | 174 | switch (number.unsignedIntegerValue) { 175 | case NSCalendarUnitYear:// 年月日 模式下用 176 | { 177 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 178 | dateComps.year = row; 179 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 180 | 181 | NSArray*dateArray = [[self.dateF stringFromDate:date] componentsSeparatedByString:KSplit]; 182 | 183 | return dateArray[component]; 184 | break; 185 | } 186 | case NSCalendarUnitMonth://年 月 日 模式下用 187 | { 188 | return [NSString stringWithFormat:@"%02zd%@",row+1,self.unitStrDict[@(NSCalendarUnitMonth)]]; 189 | break; 190 | } 191 | case NSCalendarUnitDay: 192 | { 193 | if (self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour) {//这个模式下 单独选择日期 194 | return [NSString stringWithFormat:@"%02zd%@",row+1,self.unitStrDict[@(NSCalendarUnitDay)]]; 195 | }else 196 | { 197 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 198 | dateComps.day = row; 199 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 200 | 201 | NSArray*dateArray = [[self.dateF stringFromDate:date] componentsSeparatedByString:KSplit]; 202 | 203 | return dateArray[component]; 204 | } 205 | break; 206 | } 207 | case NSCalendarUnitHour: 208 | { 209 | return [NSString stringWithFormat:@"%02zd%@",row,self.unitStrDict[@(NSCalendarUnitHour)]]; 210 | break; 211 | } 212 | case NSCalendarUnitMinute: 213 | { 214 | return [NSString stringWithFormat:@"%02zd%@",self.minuteSpace*row,self.unitStrDict[@(NSCalendarUnitMinute)]]; 215 | break; 216 | } 217 | case NSCalendarUnitSecond: 218 | { 219 | return [NSString stringWithFormat:@"%02zd%@",self.secondSpace*row,self.unitStrDict[@(NSCalendarUnitSecond)]]; 220 | break; 221 | } 222 | default: 223 | { 224 | return @"return void"; 225 | break; 226 | } 227 | } 228 | 229 | } 230 | 231 | /** 232 | * 选中完日期之后 233 | */ 234 | -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ 235 | 236 | //用于拼接日期 237 | __block NSMutableString* m_str = [NSMutableString string]; 238 | 239 | 240 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//前面拼 年 241 | //同年可用 242 | NSInteger yearRow = [self.pickerView selectedRowInComponent:0]; 243 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 244 | dateComps.day = yearRow; 245 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 246 | NSDateComponents* comps = [self.calendar components:KComUnit fromDate:date]; 247 | 248 | [m_str appendFormat:@"%@%@",[NSString stringWithFormat:@"%02zd",comps.year],self.unitStrDict[@(NSCalendarUnitYear)]]; 249 | }else if (self.pickerMode == JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//前面拼接 年月日 250 | { 251 | //同年可用 252 | NSDateComponents* comps = [self.calendar components:KComUnit fromDate:[self getMinDate]]; 253 | //yyyy年MM月dd号 254 | [m_str appendFormat:@"%@%@%@%@%@%@%@",[NSString stringWithFormat:@"%02zd",comps.year],self.unitStrDict[@(NSCalendarUnitYear)],[NSString stringWithFormat:@"%02zd",comps.month],self.unitStrDict[@(NSCalendarUnitMonth)],[NSString stringWithFormat:@"%02zd",comps.day],self.unitStrDict[@(NSCalendarUnitDay)],KSplit]; 255 | } 256 | 257 | NSArray* groupArray = self.modeDict[@(self.pickerMode)]; 258 | 259 | 260 | [groupArray enumerateObjectsUsingBlock:^(NSArray* _Nonnull unitArray, NSUInteger idxOut, BOOL * _Nonnull stop) { 261 | //拼接拆分 262 | if (idxOut!=0) { 263 | [m_str appendString:KSplit]; 264 | } 265 | //选择项 266 | NSInteger row = [self.pickerView selectedRowInComponent:idxOut]; 267 | NSString *title = [self pickerView:pickerView titleForRow:row forComponent:idxOut]; 268 | 269 | if (self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour){ 270 | //记录 day 对应的component 271 | if ([unitArray.lastObject unsignedIntegerValue]==NSCalendarUnitYear) { 272 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 273 | dateComps.year = row; 274 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 275 | self.tempDateComps.year = [self.calendar components:KComUnit fromDate:date].year; 276 | 277 | }else if ([unitArray.lastObject unsignedIntegerValue]==NSCalendarUnitMonth) 278 | { 279 | 280 | self.tempDateComps.month = row+1; 281 | } 282 | else if ([unitArray.lastObject unsignedIntegerValue]==NSCalendarUnitDay) { 283 | //获取到当前row 和刷新后的rowCount 比较 284 | NSInteger newRowCount= [self pickerView:pickerView numberOfRowsInComponent:idxOut]; 285 | if (row>=newRowCount) { 286 | [self.pickerView selectRow:newRowCount-1 inComponent:idxOut animated:NO]; 287 | 288 | title = [NSString stringWithFormat:@"%02zd%@",newRowCount,self.unitStrDict[@(NSCalendarUnitDay)]]; 289 | } 290 | [self.pickerView reloadAllComponents]; 291 | } 292 | } 293 | [m_str appendString:title]; 294 | 295 | }]; 296 | 297 | 298 | NSDate* date = [self.simpleDateF dateFromString:m_str]; 299 | 300 | if (!date) { 301 | NSLog(@"Date is nil"); 302 | return; 303 | } 304 | 305 | if(date){[self checkWithSelectedDate:date];}else{NSLog(@"Date 为 nil");} 306 | 307 | 308 | } 309 | 310 | 311 | /** 312 | * 根据选择的时间 验证最大时间和最小时间 可以择调用回调 313 | */ 314 | -(void)checkWithSelectedDate:(NSDate*)date 315 | { 316 | if ([date compare:self.maxDate]==NSOrderedDescending){ 317 | _date = self.maxDate; 318 | [self scrollToCurrentDate:self.date animated:YES]; 319 | }else if ([date compare:self.minDate]==NSOrderedAscending) { 320 | _date = self.minDate; 321 | [self scrollToCurrentDate:self.date animated:YES]; 322 | }else 323 | { 324 | _date = date; 325 | } 326 | } 327 | 328 | 329 | /** 330 | * 四舍五入 date 数据 331 | */ 332 | -(NSDate*)getRoundDateWithDate:(NSDate*)date 333 | { 334 | NSDateComponents *com = [self.calendar components:KComUnit fromDate:date]; 335 | 336 | NSInteger day = com.day; 337 | NSInteger hour = (com.hour%KHourSpace?com.hour/KHourSpace+1:com.hour/KHourSpace)*KHourSpace; 338 | NSInteger minute = (com.minute%KMinuteSpace?com.minute/KMinuteSpace+1:com.minute/KMinuteSpace)*KMinuteSpace; 339 | 340 | 341 | NSDateComponents* dateAdd = [[NSDateComponents alloc] init]; 342 | dateAdd.minute = minute - com.minute; 343 | dateAdd.hour = hour - com.hour; 344 | dateAdd.day = day - com.day; 345 | 346 | 347 | return [self.calendar dateByAddingComponents:dateAdd toDate:date options:0]; 348 | } 349 | 350 | 351 | 352 | /** 353 | * 宽度 354 | */ 355 | - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component 356 | { 357 | NSInteger coms = [self numberOfComponentsInPickerView:self.pickerView]; 358 | CGFloat width = self.bounds.size.width-(coms-1)*10; 359 | 360 | NSString* formatterStr = [self getDateFormatterWithPickModel:self.pickerMode]; 361 | NSArray* array = [formatterStr componentsSeparatedByString:KSplit]; 362 | 363 | __block NSUInteger maxLength = 0; 364 | [array enumerateObjectsUsingBlock:^(NSString* _Nonnull str, NSUInteger idx, BOOL * _Nonnull stop) { 365 | maxLength+=str.length; 366 | }]; 367 | return width/maxLength*[array[component] length]; 368 | } 369 | 370 | /** 371 | * 高度 372 | */ 373 | - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component 374 | { 375 | return (self.bounds.size.height-20)/4; 376 | } 377 | 378 | 379 | 380 | 381 | -(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view 382 | { 383 | UILabel* label = nil; 384 | if (view&&[view isKindOfClass:[UILabel class]]) { 385 | label =(UILabel*)view; 386 | }else 387 | { 388 | label= [[UILabel alloc] init]; 389 | label.textAlignment =NSTextAlignmentCenter; 390 | label.font =self.font?self.font:[UIFont systemFontOfSize:16]; 391 | } 392 | label.text = [self pickerView:pickerView titleForRow:row forComponent:component]; 393 | return label; 394 | } 395 | 396 | 397 | 398 | /** 399 | * 布局 400 | */ 401 | -(void)layoutSubviews 402 | { 403 | [super layoutSubviews]; 404 | 405 | self.bgView.frame = self.bounds; 406 | 407 | CGFloat pickerX = 0; 408 | CGFloat pickerY = 10; 409 | CGFloat pickerW = self.bounds.size.width; 410 | CGFloat pickerH = self.bounds.size.height-20; 411 | self.pickerView.frame= CGRectMake(pickerX, pickerY, pickerW, pickerH); 412 | 413 | } 414 | 415 | 416 | 417 | /** 418 | * 设置dateFormmater 419 | */ 420 | -(NSString*)getDateFormatterWithPickModel:(JWDatePickerMode)mode 421 | { 422 | __block NSMutableString* m_str = [NSMutableString string]; 423 | 424 | NSArray* groupArray = self.modeDict[@(mode)]; 425 | 426 | 427 | [groupArray enumerateObjectsUsingBlock:^(NSArray* _Nonnull unitArray, NSUInteger idx, BOOL * _Nonnull stop) { 428 | //拼接拆分 429 | if (idx!=0) { 430 | [m_str appendString:KSplit]; 431 | } 432 | //遍历模式 433 | [unitArray enumerateObjectsUsingBlock:^(NSNumber* _Nonnull unitNumber, NSUInteger idx, BOOL * _Nonnull stop) { 434 | //拼接日历格式化字符串 435 | [m_str appendString:(self.formatterDict[unitNumber])]; 436 | 437 | //拼接单位 438 | if (self.delegate&&[self.delegate respondsToSelector:@selector(datePickerView:unitForCalendarUnit:)]) { 439 | NSString* unitStr = self.unitStrDict[unitNumber]; 440 | [m_str appendString:unitStr]; 441 | } 442 | }]; 443 | }]; 444 | return m_str; 445 | 446 | } 447 | 448 | 449 | 450 | /** 451 | * 滚动到指定的位置 452 | */ 453 | -(void)reloadDataNeedScrollTo:(BOOL)need 454 | { 455 | 456 | [self.pickerView reloadAllComponents]; 457 | 458 | 459 | [self.pickerView setNeedsLayout]; 460 | 461 | 462 | if([self getCurrentDate]&&need)//滑动到显示时间 463 | { 464 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 465 | [self scrollToCurrentDate:[self getCurrentDate] animated:YES]; 466 | }); 467 | } 468 | } 469 | 470 | /** 471 | * 滚动到指定的时间 472 | */ 473 | -(void)scrollToCurrentDate:(NSDate*)date animated:(BOOL)animated 474 | { 475 | 476 | NSArray* groupUnitArray = self.modeDict[@(self.pickerMode)]; 477 | 478 | [groupUnitArray enumerateObjectsUsingBlock:^(NSArray* _Nonnull unitArray, NSUInteger idx, BOOL * _Nonnull stop) { 479 | 480 | NSNumber *number = unitArray.lastObject; 481 | //获取的对应的组的rowCount 482 | NSInteger maxRowCount = [self pickerView:self.pickerView numberOfRowsInComponent:idx]; 483 | //分项处理 484 | switch (number.unsignedIntegerValue) { 485 | case NSCalendarUnitYear:// 年月日 模式下用 486 | { 487 | NSInteger year= [self.calendar component:number.unsignedIntegerValue fromDate:date]-[self.calendar component:number.unsignedIntegerValue fromDate:[self getMinDate]]; 488 | 489 | if (year*)modeDict 710 | { 711 | if (_modeDict==nil) { 712 | _modeDict = [NSMutableDictionary dictionary]; 713 | // JWDatePickerMode_DateAndTime,// 年月日 时分秒 714 | _modeDict[@(JWDatePickerMode_DateAndTime)]= @[@[@(NSCalendarUnitYear),@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)],@[@(NSCalendarUnitSecond)]]; 715 | 716 | // JWDatePickerMode_Time,// 时分秒 717 | _modeDict[@(JWDatePickerMode_Time)]= @[@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)],@[@(NSCalendarUnitSecond)]]; 718 | 719 | 720 | // JWDatePickerMode_TimeRSecond,// 时分 721 | _modeDict[@(JWDatePickerMode_TimeRSecond)]= @[@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)]]; 722 | 723 | // JWDatePickerMode_Date,// 年月日 724 | _modeDict[@(JWDatePickerMode_Date)]= @[@[@(NSCalendarUnitYear)],@[@(NSCalendarUnitMonth)],@[@(NSCalendarUnitDay)]]; 725 | 726 | // JWDatePickerMode_DateAndTimeRYear,// 月日 时 分 秒 727 | _modeDict[@(JWDatePickerMode_DateAndTimeRYear)]= @[@[@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)],@[@(NSCalendarUnitSecond)]]; 728 | 729 | // JWDatePickerMode_DateAddHour,// 年月日 时 分 730 | _modeDict[@(JWDatePickerMode_DateAddHour)]= @[@[@(NSCalendarUnitYear)],@[@(NSCalendarUnitMonth)],@[@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)]]; 731 | 732 | // JWDatePickerMode_DateAndTimeRSecond,// 年月日 时 分 733 | _modeDict[@(JWDatePickerMode_DateAndTimeRSecond)]= @[@[@(NSCalendarUnitYear),@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)]]; 734 | 735 | 736 | // JWDatePickerMode_DateAndTimeRYearAndSecond,//月日 时分 737 | _modeDict[@(JWDatePickerMode_DateAndTimeRYearAndSecond)]= @[@[@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)]]; 738 | 739 | } 740 | 741 | return _modeDict; 742 | } 743 | 744 | /** 745 | * 格式化字符串 746 | */ 747 | -(NSDateFormatter *)dateF 748 | { 749 | if (_dateF==nil) { 750 | _dateF = [[NSDateFormatter alloc] init]; 751 | } 752 | return _dateF; 753 | } 754 | 755 | -(NSMutableDictionary *)unitStrDict 756 | { 757 | if (_unitStrDict ==nil&&self.delegate) { 758 | _unitStrDict = [NSMutableDictionary dictionary]; 759 | 760 | [self.formatterDict enumerateKeysAndObjectsUsingBlock:^(NSNumber* _Nonnull unitNumber, id _Nonnull obj, BOOL * _Nonnull stop) { 761 | 762 | NSString* unitStr = @""; 763 | 764 | if (self.delegate&&[self.delegate respondsToSelector:@selector(datePickerView:unitForCalendarUnit:)]) { 765 | unitStr = [self.delegate datePickerView:self unitForCalendarUnit:unitNumber.unsignedIntegerValue]; 766 | //验证拆分 767 | if([unitStr rangeOfString:KSplit].location!=NSNotFound) 768 | { 769 | unitStr = @""; 770 | } 771 | } 772 | _unitStrDict[unitNumber] = unitStr; 773 | }]; 774 | 775 | } 776 | return _unitStrDict; 777 | } 778 | 779 | /** 780 | * 格式化 781 | */ 782 | -(NSMutableDictionary *)formatterDict 783 | { 784 | if (_formatterDict ==nil) { 785 | _formatterDict = [NSMutableDictionary dictionary]; 786 | _formatterDict[@(NSCalendarUnitYear)]= @"yyyy"; 787 | _formatterDict[@(NSCalendarUnitMonth)]= @"MM"; 788 | _formatterDict[@(NSCalendarUnitDay)]= @"dd"; 789 | _formatterDict[@(NSCalendarUnitHour)]= @"HH"; 790 | _formatterDict[@(NSCalendarUnitMinute)]= @"mm"; 791 | _formatterDict[@(NSCalendarUnitSecond)]= @"ss"; 792 | } 793 | return _formatterDict; 794 | } 795 | 796 | /** 797 | * 设置日期格式 798 | */ 799 | -(void)setDateFDateFormatter 800 | { 801 | //1.获取到当前模式下的 格式化字符串 802 | NSString *dateFormatterStr = [self getDateFormatterWithPickModel:self.pickerMode]; 803 | self.dateF.dateFormat = dateFormatterStr; 804 | 805 | //2.拼接 转换选中模式下的格式化字符串 806 | NSString* sourceFormatter = @""; 807 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//前面拼 年 808 | sourceFormatter = [NSString stringWithFormat:@"yyyy%@",self.unitStrDict[@(NSCalendarUnitYear)]]; 809 | }else if (self.pickerMode == JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//前面拼接 年月日 810 | { 811 | sourceFormatter =[NSString stringWithFormat:@"yyyy%@MM%@dd%@%@",self.unitStrDict[@(NSCalendarUnitYear)],self.unitStrDict[@(NSCalendarUnitMonth)],self.unitStrDict[@(NSCalendarUnitDay)],KSplit]; 812 | } 813 | 814 | //3.完整拼接 815 | NSString* lastFormatterStr = [NSString stringWithFormat:@"%@%@",sourceFormatter,dateFormatterStr]; 816 | 817 | //4.设置格式化字符串 818 | self.simpleDateF.dateFormat= lastFormatterStr; 819 | 820 | } 821 | 822 | 823 | 824 | /** 825 | * 获取最大时间 826 | */ 827 | -(NSDate*)getMinDate 828 | { 829 | if (self.minDate==nil) { 830 | 831 | if (self.maxDate) {//设置 最小日期的时候 832 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//同一年 833 | NSDateComponents *addComps = [[NSDateComponents alloc] init]; 834 | addComps.year = -1; 835 | addComps.day = 1; 836 | self.minDate = [self.calendar dateByAddingComponents:addComps toDate:self.maxDate options:NSCalendarMatchLast]; 837 | }else if (self.pickerMode==JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//同一天 838 | { 839 | self.minDate = [self getDayLastDateWithDate:self.maxDate max:NO]; 840 | } 841 | else{ 842 | NSDateComponents* comps = [[NSDateComponents alloc] init]; 843 | comps.year = -1; 844 | self.minDate = [self.calendar dateByAddingComponents:comps toDate:self.maxDate options:NSCalendarMatchLast]; 845 | } 846 | }else 847 | { 848 | self.minDate = [NSDate date]; 849 | } 850 | } 851 | return self.minDate; 852 | } 853 | 854 | /** 855 | * 获取最小时间 856 | */ 857 | -(NSDate*)getMaxDate 858 | { 859 | if (self.maxDate ==nil) { 860 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//同一年 861 | NSDateComponents *addComps = [[NSDateComponents alloc] init]; 862 | addComps.year = 1; 863 | addComps.day = -1; 864 | _maxDate = [self.calendar dateByAddingComponents:addComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 865 | }else if (self.pickerMode==JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//同一天 866 | { 867 | _maxDate = [self getDayLastDateWithDate:self.minDate max:YES]; 868 | } 869 | else{ 870 | NSDateComponents* comps = [[NSDateComponents alloc] init]; 871 | comps.year = 1; 872 | _maxDate = [self.calendar dateByAddingComponents:comps toDate:[self getMinDate] options:NSCalendarMatchLast]; 873 | } 874 | } 875 | return self.maxDate; 876 | } 877 | 878 | /** 879 | * 获取当前时间 880 | */ 881 | -(NSDate*)getCurrentDate 882 | { 883 | if (self.date ==nil) { 884 | self.date = [self getMinDate]; 885 | } 886 | return self.date; 887 | } 888 | 889 | 890 | 891 | /** 892 | * 切换模式时刷新 893 | */ 894 | -(void)setPickerMode:(JWDatePickerMode)pickerMode 895 | { 896 | 897 | _pickerMode = pickerMode; 898 | 899 | 900 | [self setDateFDateFormatter]; 901 | 902 | //年 月 日 单选 903 | if(self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour){ 904 | if (!self.date) { 905 | self.date = [self getMinDate]; 906 | } 907 | NSDateComponents *comps= [self.calendar components:KComUnit fromDate:self.date]; 908 | self.tempDateComps.year=comps.year; 909 | self.tempDateComps.month = comps.month; 910 | } 911 | 912 | if (self.minDate&&self.maxDate) { 913 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//同一年 914 | // 最小时间1年后的时间 compare 最大时间 915 | NSDateComponents *addComps = [[NSDateComponents alloc] init]; 916 | addComps.year = 1; 917 | addComps.day = -1; 918 | NSDate* lastMaxDate = [self.calendar dateByAddingComponents:addComps toDate:self.minDate options:NSCalendarMatchLast]; 919 | if ([lastMaxDate compare:self.maxDate]==NSOrderedAscending) { 920 | 921 | self.maxDate = lastMaxDate; 922 | [self.pickerView reloadAllComponents]; 923 | } 924 | }else if (self.pickerMode==JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//同一天 925 | { 926 | NSDate* lastMaxDate = [self getDayLastDateWithDate:self.minDate max:YES]; 927 | 928 | if ([lastMaxDate compare:self.maxDate]==NSOrderedAscending) { 929 | self.maxDate = lastMaxDate; 930 | [self.pickerView reloadAllComponents]; 931 | } 932 | } 933 | } 934 | 935 | [self reloadDataNeedScrollTo:YES]; 936 | 937 | } 938 | 939 | /** 940 | * 设置代理是刷新 941 | */ 942 | -(void)setDelegate:(id)delegate 943 | { 944 | if (delegate) { 945 | _delegate = delegate; 946 | 947 | [self setDateFDateFormatter]; 948 | 949 | [self reloadData]; 950 | } 951 | } 952 | 953 | /** 954 | * 用于转换 选择的时间 955 | */ 956 | -(NSDateFormatter *)simpleDateF 957 | { 958 | if (_simpleDateF==nil) { 959 | _simpleDateF = [[NSDateFormatter alloc] init]; 960 | } 961 | return _simpleDateF; 962 | } 963 | 964 | 965 | /** 966 | * 限制间隔 967 | */ 968 | -(void)setMinuteSpace:(NSUInteger)minuteSpace 969 | { 970 | if (minuteSpace<30&&60%minuteSpace==0) { 971 | _minuteSpace = minuteSpace; 972 | } 973 | 974 | } 975 | 976 | /** 977 | * 限制间隔 978 | */ 979 | -(void)setSecondSpace:(NSUInteger)secondSpace 980 | { 981 | if (secondSpace<30&&60%secondSpace==0) { 982 | _secondSpace = secondSpace; 983 | } 984 | } 985 | 986 | 987 | /** 988 | * 是否是闰年 989 | */ 990 | -(BOOL)isLeapYear:(NSInteger)year 991 | { 992 | if (year%4==0) { 993 | if (year%100==0) { 994 | if (year%400==0) { 995 | return YES; 996 | } 997 | //能被 4 100 整除 不能被400 整除的 不是闰年 998 | return NO; 999 | } 1000 | //能被4整除 不能被100整除的 是闰年 1001 | return YES; 1002 | } 1003 | //不能为4整除 不是闰年 1004 | return NO; 1005 | } 1006 | 1007 | /** 1008 | * 根据对应的年 和月 返回当月对应的天数 1009 | */ 1010 | -(NSInteger)getMonthDaysWithYear:(NSInteger)year andMoth:(NSInteger)moth 1011 | { 1012 | // 31 28 31 30 31 30 31 31 30 31 30 31 1013 | NSArray *daysOfMonth=@[@31,@28,@31,@30,@31,@30,@31,@31,@30,@31,@30,@31]; 1014 | 1015 | NSUInteger days=[daysOfMonth[moth-1] integerValue]; 1016 | 1017 | if (days==28) { 1018 | if ([self isLeapYear:year])days=29; 1019 | } 1020 | return days; 1021 | } 1022 | 1023 | -(NSDateComponents *)tempDateComps 1024 | { 1025 | if (_tempDateComps==nil) { 1026 | _tempDateComps = [[NSDateComponents alloc] init]; 1027 | } 1028 | return _tempDateComps; 1029 | } 1030 | 1031 | 1032 | -(NSString *)getDateStrWithDateFormatterString:(NSString *)formatterStr 1033 | { 1034 | if (self.date&&formatterStr&&formatterStr.length) { 1035 | 1036 | } 1037 | return @"格式化字符串不合法"; 1038 | } 1039 | 1040 | -(NSString *)getDateStr 1041 | { 1042 | if (self.date) { 1043 | return [[self.simpleDateF stringFromDate:self.date] stringByReplacingOccurrencesOfString:KSplit withString:@""]; 1044 | } 1045 | return @"NO Date"; 1046 | } 1047 | 1048 | /** 1049 | * 获取一天中的 最小时间 最大时间 1050 | */ 1051 | -(NSDate*)getDayLastDateWithDate:(NSDate*)date max:(BOOL)isGetMax 1052 | { 1053 | if (!date) { 1054 | return [NSDate date]; 1055 | } 1056 | 1057 | NSDateComponents*dateComps = [self.calendar components:KComUnit fromDate:date]; 1058 | NSInteger hour = dateComps.hour; 1059 | NSInteger minute = dateComps.minute; 1060 | NSInteger second = dateComps.second; 1061 | 1062 | NSDateComponents *newDateComp = [NSDateComponents new]; 1063 | if (isGetMax) { 1064 | newDateComp.hour = 24-hour-1; 1065 | newDateComp.minute = 60 - minute -1; 1066 | newDateComp.second = 60 - second -1; 1067 | }else 1068 | { 1069 | newDateComp.hour = -hour; 1070 | newDateComp.minute = -minute; 1071 | newDateComp.second = -second; 1072 | } 1073 | NSDate* lastDate = [self.calendar dateByAddingComponents:newDateComp toDate:date options:NSCalendarMatchLast]; 1074 | return lastDate; 1075 | } 1076 | @end 1077 | -------------------------------------------------------------------------------- /Demo/JWDatePickerView/JWDatePickerView/JWDatePickerView/JWDatePickerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JWDatePickerView.m 3 | // JWDatePickerView 4 | // 5 | // Created by 朱建伟 on 16/7/19. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | #define KSplit @"(#拆#)"//用来拆分 9 | 10 | #define KTotalFormatter @"yyyy MM dd HH mm ss" 11 | #define KTotalFormatterStr @"%@ %@ %@ %@ %@ %@" 12 | 13 | #define KComUnit NSCalendarUnitYear|NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond 14 | 15 | 16 | #import "JWDatePickerView.h" 17 | 18 | @interface JWDatePickerView() 19 | /** 20 | * bgView 21 | */ 22 | @property(nonatomic,strong)UIView* bgView; 23 | /** 24 | * pickerView 25 | */ 26 | @property(nonatomic,strong)UIPickerView* pickerView; 27 | 28 | /** 29 | * modeDict 30 | */ 31 | @property(nonatomic,strong)NSMutableDictionary* modeDict; 32 | /** 33 | * formatterDict 34 | */ 35 | @property(nonatomic,strong)NSMutableDictionary* formatterDict; 36 | 37 | /** 38 | * unitdict 39 | */ 40 | @property(nonatomic,strong)NSMutableDictionary* unitStrDict; 41 | 42 | /** 43 | * calendar 44 | */ 45 | @property(nonatomic,strong)NSCalendar* calendar; 46 | 47 | /** 48 | * dateFormmater 49 | */ 50 | @property(nonatomic,strong)NSDateFormatter* dateF; 51 | 52 | 53 | /** 54 | * formmater 55 | */ 56 | @property(nonatomic,strong)NSDateFormatter* simpleDateF; 57 | 58 | /** 59 | * tempComps 60 | */ 61 | @property(nonatomic,strong)NSDateComponents *tempDateComps; 62 | 63 | 64 | @end 65 | 66 | @implementation JWDatePickerView 67 | 68 | /** 69 | * 初始化控件 70 | */ 71 | -(instancetype)initWithFrame:(CGRect)frame 72 | { 73 | if (self = [super initWithFrame:frame]) { 74 | self.minuteSpace = 1; 75 | self.secondSpace = 1; 76 | 77 | self.bgView = [[UIView alloc] init]; 78 | [self addSubview:self.bgView]; 79 | 80 | //模式 81 | self.pickerMode = JWDatePickerMode_DateAddHour; 82 | self.font = [UIFont boldSystemFontOfSize:16]; 83 | 84 | //pickerView 85 | self.pickerView = [[UIPickerView alloc] init]; 86 | self.pickerView.backgroundColor = [UIColor whiteColor]; 87 | self.pickerView.delegate = self; 88 | self.pickerView.dataSource = self; 89 | [self.bgView addSubview:self.pickerView]; 90 | 91 | } 92 | return self; 93 | } 94 | 95 | 96 | - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView 97 | { 98 | //返回对应模式下的compsCount 99 | // if (self.pickerMode==JWDatePickerMode_DateAndTime||self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAddHour) { 100 | // return 4; 101 | // }else if (self.pickerMode==JWDatePickerMode_TimeRSecond) 102 | // { 103 | // return 2; 104 | // } 105 | // return 3; 106 | return [self.modeDict objectForKey:@(self.pickerMode)].count; 107 | } 108 | 109 | 110 | - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component 111 | { 112 | NSArray* groupUnitArray = self.modeDict[@(self.pickerMode)]; 113 | if (component>=groupUnitArray.count) { 114 | return 0; 115 | } 116 | NSNumber* number = [groupUnitArray[component] lastObject]; 117 | 118 | switch (number.unsignedIntegerValue) { 119 | case NSCalendarUnitYear: 120 | { 121 | NSInteger year= [self.calendar component:number.unsignedIntegerValue fromDate:[self getMaxDate]]-[self.calendar component:number.unsignedIntegerValue fromDate:[self getMinDate]]+1; 122 | 123 | 124 | return year; 125 | break; 126 | } 127 | case NSCalendarUnitMonth: 128 | return 12; 129 | break; 130 | case NSCalendarUnitDay: 131 | { 132 | if (self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour) {//这个模式下 年 月 日 或者 年 月 日 时 133 | //根据年月日刷新 天数 134 | NSInteger days =[self getMonthDaysWithYear:self.tempDateComps.year andMoth:self.tempDateComps.month]; 135 | return days; 136 | }else 137 | { 138 | 139 | return [self.calendar components:number.unsignedIntegerValue fromDate:[self getMinDate] toDate:[self getMaxDate] options:NSCalendarMatchLast].day+1; 140 | } 141 | break; 142 | } 143 | case NSCalendarUnitHour: 144 | return 24; 145 | break; 146 | 147 | case NSCalendarUnitMinute: 148 | return 60/self.minuteSpace; 149 | break; 150 | 151 | case NSCalendarUnitSecond: 152 | return 60/self.secondSpace; 153 | break; 154 | default: 155 | break; 156 | } 157 | 158 | return 1; 159 | } 160 | 161 | 162 | 163 | -(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component 164 | { 165 | 166 | 167 | NSArray* groupUnitArray = self.modeDict[@(self.pickerMode)]; 168 | 169 | if (component>=groupUnitArray.count) { 170 | return @""; 171 | } 172 | NSNumber* number = [groupUnitArray[component] lastObject]; 173 | 174 | switch (number.unsignedIntegerValue) { 175 | case NSCalendarUnitYear:// 年月日 模式下用 176 | { 177 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 178 | dateComps.year = row; 179 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 180 | 181 | NSArray*dateArray = [[self.dateF stringFromDate:date] componentsSeparatedByString:KSplit]; 182 | 183 | return dateArray[component]; 184 | break; 185 | } 186 | case NSCalendarUnitMonth://年 月 日 模式下用 187 | { 188 | return [NSString stringWithFormat:@"%02zd%@",row+1,self.unitStrDict[@(NSCalendarUnitMonth)]]; 189 | break; 190 | } 191 | case NSCalendarUnitDay: 192 | { 193 | if (self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour) {//这个模式下 单独选择日期 194 | return [NSString stringWithFormat:@"%02zd%@",row+1,self.unitStrDict[@(NSCalendarUnitDay)]]; 195 | }else 196 | { 197 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 198 | dateComps.day = row; 199 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 200 | 201 | NSArray*dateArray = [[self.dateF stringFromDate:date] componentsSeparatedByString:KSplit]; 202 | 203 | return dateArray[component]; 204 | } 205 | break; 206 | } 207 | case NSCalendarUnitHour: 208 | { 209 | return [NSString stringWithFormat:@"%02zd%@",row,self.unitStrDict[@(NSCalendarUnitHour)]]; 210 | break; 211 | } 212 | case NSCalendarUnitMinute: 213 | { 214 | return [NSString stringWithFormat:@"%02zd%@",self.minuteSpace*row,self.unitStrDict[@(NSCalendarUnitMinute)]]; 215 | break; 216 | } 217 | case NSCalendarUnitSecond: 218 | { 219 | return [NSString stringWithFormat:@"%02zd%@",self.secondSpace*row,self.unitStrDict[@(NSCalendarUnitSecond)]]; 220 | break; 221 | } 222 | default: 223 | { 224 | return @"return void"; 225 | break; 226 | } 227 | } 228 | 229 | } 230 | 231 | /** 232 | * 选中完日期之后 233 | */ 234 | -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ 235 | 236 | //用于拼接日期 237 | __block NSMutableString* m_str = [NSMutableString string]; 238 | 239 | 240 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//前面拼 年 241 | //同年可用 242 | NSInteger yearRow = [self.pickerView selectedRowInComponent:0]; 243 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 244 | dateComps.day = yearRow; 245 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 246 | NSDateComponents* comps = [self.calendar components:KComUnit fromDate:date]; 247 | 248 | [m_str appendFormat:@"%@%@",[NSString stringWithFormat:@"%02zd",comps.year],self.unitStrDict[@(NSCalendarUnitYear)]]; 249 | }else if (self.pickerMode == JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//前面拼接 年月日 250 | { 251 | //同年可用 252 | NSDateComponents* comps = [self.calendar components:KComUnit fromDate:[self getMinDate]]; 253 | //yyyy年MM月dd号 254 | [m_str appendFormat:@"%@%@%@%@%@%@%@",[NSString stringWithFormat:@"%02zd",comps.year],self.unitStrDict[@(NSCalendarUnitYear)],[NSString stringWithFormat:@"%02zd",comps.month],self.unitStrDict[@(NSCalendarUnitMonth)],[NSString stringWithFormat:@"%02zd",comps.day],self.unitStrDict[@(NSCalendarUnitDay)],KSplit]; 255 | } 256 | 257 | NSArray* groupArray = self.modeDict[@(self.pickerMode)]; 258 | 259 | 260 | [groupArray enumerateObjectsUsingBlock:^(NSArray* _Nonnull unitArray, NSUInteger idxOut, BOOL * _Nonnull stop) { 261 | //拼接拆分 262 | if (idxOut!=0) { 263 | [m_str appendString:KSplit]; 264 | } 265 | //选择项 266 | NSInteger row = [self.pickerView selectedRowInComponent:idxOut]; 267 | NSString *title = [self pickerView:pickerView titleForRow:row forComponent:idxOut]; 268 | 269 | if (self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour){ 270 | //记录 day 对应的component 271 | if ([unitArray.lastObject unsignedIntegerValue]==NSCalendarUnitYear) { 272 | NSDateComponents*dateComps = [[NSDateComponents alloc] init]; 273 | dateComps.year = row; 274 | NSDate* date = [self.calendar dateByAddingComponents:dateComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 275 | self.tempDateComps.year = [self.calendar components:KComUnit fromDate:date].year; 276 | 277 | }else if ([unitArray.lastObject unsignedIntegerValue]==NSCalendarUnitMonth) 278 | { 279 | 280 | self.tempDateComps.month = row+1; 281 | } 282 | else if ([unitArray.lastObject unsignedIntegerValue]==NSCalendarUnitDay) { 283 | //获取到当前row 和刷新后的rowCount 比较 284 | NSInteger newRowCount= [self pickerView:pickerView numberOfRowsInComponent:idxOut]; 285 | if (row>=newRowCount) { 286 | [self.pickerView selectRow:newRowCount-1 inComponent:idxOut animated:NO]; 287 | 288 | title = [NSString stringWithFormat:@"%02zd%@",newRowCount,self.unitStrDict[@(NSCalendarUnitDay)]]; 289 | } 290 | [self.pickerView reloadAllComponents]; 291 | } 292 | } 293 | [m_str appendString:title]; 294 | 295 | }]; 296 | 297 | 298 | NSDate* date = [self.simpleDateF dateFromString:m_str]; 299 | 300 | if (!date) { 301 | NSLog(@"Date is nil"); 302 | return; 303 | } 304 | 305 | if(date){[self checkWithSelectedDate:date];}else{NSLog(@"Date 为 nil");} 306 | 307 | 308 | } 309 | 310 | 311 | /** 312 | * 根据选择的时间 验证最大时间和最小时间 可以择调用回调 313 | */ 314 | -(void)checkWithSelectedDate:(NSDate*)date 315 | { 316 | if ([date compare:self.maxDate]==NSOrderedDescending){ 317 | _date = self.maxDate; 318 | [self scrollToCurrentDate:self.date animated:YES]; 319 | }else if ([date compare:self.minDate]==NSOrderedAscending) { 320 | _date = self.minDate; 321 | [self scrollToCurrentDate:self.date animated:YES]; 322 | }else 323 | { 324 | _date = date; 325 | } 326 | } 327 | 328 | 329 | /** 330 | * 四舍五入 date 数据 331 | */ 332 | -(NSDate*)getRoundDateWithDate:(NSDate*)date 333 | { 334 | NSDateComponents *com = [self.calendar components:KComUnit fromDate:date]; 335 | 336 | NSInteger day = com.day; 337 | NSInteger hour = (com.hour%KHourSpace?com.hour/KHourSpace+1:com.hour/KHourSpace)*KHourSpace; 338 | NSInteger minute = (com.minute%KMinuteSpace?com.minute/KMinuteSpace+1:com.minute/KMinuteSpace)*KMinuteSpace; 339 | 340 | 341 | NSDateComponents* dateAdd = [[NSDateComponents alloc] init]; 342 | dateAdd.minute = minute - com.minute; 343 | dateAdd.hour = hour - com.hour; 344 | dateAdd.day = day - com.day; 345 | 346 | 347 | return [self.calendar dateByAddingComponents:dateAdd toDate:date options:0]; 348 | } 349 | 350 | 351 | 352 | /** 353 | * 宽度 354 | */ 355 | - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component 356 | { 357 | NSInteger coms = [self numberOfComponentsInPickerView:self.pickerView]; 358 | CGFloat width = self.bounds.size.width-(coms-1)*10; 359 | 360 | NSString* formatterStr = [self getDateFormatterWithPickModel:self.pickerMode]; 361 | NSArray* array = [formatterStr componentsSeparatedByString:KSplit]; 362 | 363 | __block NSUInteger maxLength = 0; 364 | [array enumerateObjectsUsingBlock:^(NSString* _Nonnull str, NSUInteger idx, BOOL * _Nonnull stop) { 365 | maxLength+=str.length; 366 | }]; 367 | return width/maxLength*[array[component] length]; 368 | } 369 | 370 | /** 371 | * 高度 372 | */ 373 | - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component 374 | { 375 | return (self.bounds.size.height-20)/4; 376 | } 377 | 378 | 379 | 380 | 381 | -(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view 382 | { 383 | UILabel* label = nil; 384 | if (view&&[view isKindOfClass:[UILabel class]]) { 385 | label =(UILabel*)view; 386 | }else 387 | { 388 | label= [[UILabel alloc] init]; 389 | label.textAlignment =NSTextAlignmentCenter; 390 | label.font =self.font?self.font:[UIFont systemFontOfSize:16]; 391 | } 392 | label.text = [self pickerView:pickerView titleForRow:row forComponent:component]; 393 | return label; 394 | } 395 | 396 | 397 | 398 | /** 399 | * 布局 400 | */ 401 | -(void)layoutSubviews 402 | { 403 | [super layoutSubviews]; 404 | 405 | self.bgView.frame = self.bounds; 406 | 407 | CGFloat pickerX = 0; 408 | CGFloat pickerY = 10; 409 | CGFloat pickerW = self.bounds.size.width; 410 | CGFloat pickerH = self.bounds.size.height-20; 411 | self.pickerView.frame= CGRectMake(pickerX, pickerY, pickerW, pickerH); 412 | 413 | } 414 | 415 | 416 | 417 | /** 418 | * 设置dateFormmater 419 | */ 420 | -(NSString*)getDateFormatterWithPickModel:(JWDatePickerMode)mode 421 | { 422 | __block NSMutableString* m_str = [NSMutableString string]; 423 | 424 | NSArray* groupArray = self.modeDict[@(mode)]; 425 | 426 | 427 | [groupArray enumerateObjectsUsingBlock:^(NSArray* _Nonnull unitArray, NSUInteger idx, BOOL * _Nonnull stop) { 428 | //拼接拆分 429 | if (idx!=0) { 430 | [m_str appendString:KSplit]; 431 | } 432 | //遍历模式 433 | [unitArray enumerateObjectsUsingBlock:^(NSNumber* _Nonnull unitNumber, NSUInteger idx, BOOL * _Nonnull stop) { 434 | //拼接日历格式化字符串 435 | [m_str appendString:(self.formatterDict[unitNumber])]; 436 | 437 | //拼接单位 438 | if (self.delegate&&[self.delegate respondsToSelector:@selector(datePickerView:unitForCalendarUnit:)]) { 439 | NSString* unitStr = self.unitStrDict[unitNumber]; 440 | [m_str appendString:unitStr]; 441 | } 442 | }]; 443 | }]; 444 | return m_str; 445 | 446 | } 447 | 448 | 449 | 450 | /** 451 | * 滚动到指定的位置 452 | */ 453 | -(void)reloadDataNeedScrollTo:(BOOL)need 454 | { 455 | 456 | [self.pickerView reloadAllComponents]; 457 | 458 | 459 | [self.pickerView setNeedsLayout]; 460 | 461 | 462 | if([self getCurrentDate]&&need)//滑动到显示时间 463 | { 464 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 465 | [self scrollToCurrentDate:[self getCurrentDate] animated:YES]; 466 | }); 467 | } 468 | } 469 | 470 | /** 471 | * 滚动到指定的时间 472 | */ 473 | -(void)scrollToCurrentDate:(NSDate*)date animated:(BOOL)animated 474 | { 475 | 476 | NSArray* groupUnitArray = self.modeDict[@(self.pickerMode)]; 477 | 478 | [groupUnitArray enumerateObjectsUsingBlock:^(NSArray* _Nonnull unitArray, NSUInteger idx, BOOL * _Nonnull stop) { 479 | 480 | NSNumber *number = unitArray.lastObject; 481 | //获取的对应的组的rowCount 482 | NSInteger maxRowCount = [self pickerView:self.pickerView numberOfRowsInComponent:idx]; 483 | //分项处理 484 | switch (number.unsignedIntegerValue) { 485 | case NSCalendarUnitYear:// 年月日 模式下用 486 | { 487 | NSInteger year= [self.calendar component:number.unsignedIntegerValue fromDate:date]-[self.calendar component:number.unsignedIntegerValue fromDate:[self getMinDate]]; 488 | 489 | if (year*)modeDict 710 | { 711 | if (_modeDict==nil) { 712 | _modeDict = [NSMutableDictionary dictionary]; 713 | // JWDatePickerMode_DateAndTime,// 年月日 时分秒 714 | _modeDict[@(JWDatePickerMode_DateAndTime)]= @[@[@(NSCalendarUnitYear),@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)],@[@(NSCalendarUnitSecond)]]; 715 | 716 | // JWDatePickerMode_Time,// 时分秒 717 | _modeDict[@(JWDatePickerMode_Time)]= @[@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)],@[@(NSCalendarUnitSecond)]]; 718 | 719 | 720 | // JWDatePickerMode_TimeRSecond,// 时分 721 | _modeDict[@(JWDatePickerMode_TimeRSecond)]= @[@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)]]; 722 | 723 | // JWDatePickerMode_Date,// 年月日 724 | _modeDict[@(JWDatePickerMode_Date)]= @[@[@(NSCalendarUnitYear)],@[@(NSCalendarUnitMonth)],@[@(NSCalendarUnitDay)]]; 725 | 726 | // JWDatePickerMode_DateAndTimeRYear,// 月日 时 分 秒 727 | _modeDict[@(JWDatePickerMode_DateAndTimeRYear)]= @[@[@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)],@[@(NSCalendarUnitSecond)]]; 728 | 729 | // JWDatePickerMode_DateAddHour,// 年月日 时 分 730 | _modeDict[@(JWDatePickerMode_DateAddHour)]= @[@[@(NSCalendarUnitYear)],@[@(NSCalendarUnitMonth)],@[@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)]]; 731 | 732 | // JWDatePickerMode_DateAndTimeRSecond,// 年月日 时 分 733 | _modeDict[@(JWDatePickerMode_DateAndTimeRSecond)]= @[@[@(NSCalendarUnitYear),@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)]]; 734 | 735 | 736 | // JWDatePickerMode_DateAndTimeRYearAndSecond,//月日 时分 737 | _modeDict[@(JWDatePickerMode_DateAndTimeRYearAndSecond)]= @[@[@(NSCalendarUnitMonth),@(NSCalendarUnitDay)],@[@(NSCalendarUnitHour)],@[@(NSCalendarUnitMinute)]]; 738 | 739 | } 740 | 741 | return _modeDict; 742 | } 743 | 744 | /** 745 | * 格式化字符串 746 | */ 747 | -(NSDateFormatter *)dateF 748 | { 749 | if (_dateF==nil) { 750 | _dateF = [[NSDateFormatter alloc] init]; 751 | } 752 | return _dateF; 753 | } 754 | 755 | -(NSMutableDictionary *)unitStrDict 756 | { 757 | if (_unitStrDict ==nil&&self.delegate) { 758 | _unitStrDict = [NSMutableDictionary dictionary]; 759 | 760 | [self.formatterDict enumerateKeysAndObjectsUsingBlock:^(NSNumber* _Nonnull unitNumber, id _Nonnull obj, BOOL * _Nonnull stop) { 761 | 762 | NSString* unitStr = @""; 763 | 764 | if (self.delegate&&[self.delegate respondsToSelector:@selector(datePickerView:unitForCalendarUnit:)]) { 765 | unitStr = [self.delegate datePickerView:self unitForCalendarUnit:unitNumber.unsignedIntegerValue]; 766 | //验证拆分 767 | if([unitStr rangeOfString:KSplit].location!=NSNotFound) 768 | { 769 | unitStr = @""; 770 | } 771 | } 772 | _unitStrDict[unitNumber] = unitStr; 773 | }]; 774 | 775 | } 776 | return _unitStrDict; 777 | } 778 | 779 | /** 780 | * 格式化 781 | */ 782 | -(NSMutableDictionary *)formatterDict 783 | { 784 | if (_formatterDict ==nil) { 785 | _formatterDict = [NSMutableDictionary dictionary]; 786 | _formatterDict[@(NSCalendarUnitYear)]= @"yyyy"; 787 | _formatterDict[@(NSCalendarUnitMonth)]= @"MM"; 788 | _formatterDict[@(NSCalendarUnitDay)]= @"dd"; 789 | _formatterDict[@(NSCalendarUnitHour)]= @"HH"; 790 | _formatterDict[@(NSCalendarUnitMinute)]= @"mm"; 791 | _formatterDict[@(NSCalendarUnitSecond)]= @"ss"; 792 | } 793 | return _formatterDict; 794 | } 795 | 796 | /** 797 | * 设置日期格式 798 | */ 799 | -(void)setDateFDateFormatter 800 | { 801 | //1.获取到当前模式下的 格式化字符串 802 | NSString *dateFormatterStr = [self getDateFormatterWithPickModel:self.pickerMode]; 803 | self.dateF.dateFormat = dateFormatterStr; 804 | 805 | //2.拼接 转换选中模式下的格式化字符串 806 | NSString* sourceFormatter = @""; 807 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//前面拼 年 808 | sourceFormatter = [NSString stringWithFormat:@"yyyy%@",self.unitStrDict[@(NSCalendarUnitYear)]]; 809 | }else if (self.pickerMode == JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//前面拼接 年月日 810 | { 811 | sourceFormatter =[NSString stringWithFormat:@"yyyy%@MM%@dd%@%@",self.unitStrDict[@(NSCalendarUnitYear)],self.unitStrDict[@(NSCalendarUnitMonth)],self.unitStrDict[@(NSCalendarUnitDay)],KSplit]; 812 | } 813 | 814 | //3.完整拼接 815 | NSString* lastFormatterStr = [NSString stringWithFormat:@"%@%@",sourceFormatter,dateFormatterStr]; 816 | 817 | //4.设置格式化字符串 818 | self.simpleDateF.dateFormat= lastFormatterStr; 819 | 820 | } 821 | 822 | 823 | 824 | /** 825 | * 获取最大时间 826 | */ 827 | -(NSDate*)getMinDate 828 | { 829 | if (self.minDate==nil) { 830 | 831 | if (self.maxDate) {//设置 最小日期的时候 832 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//同一年 833 | NSDateComponents *addComps = [[NSDateComponents alloc] init]; 834 | addComps.year = -1; 835 | addComps.day = 1; 836 | self.minDate = [self.calendar dateByAddingComponents:addComps toDate:self.maxDate options:NSCalendarMatchLast]; 837 | }else if (self.pickerMode==JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//同一天 838 | { 839 | self.minDate = [self getDayLastDateWithDate:self.maxDate max:NO]; 840 | } 841 | else{ 842 | NSDateComponents* comps = [[NSDateComponents alloc] init]; 843 | comps.year = -1; 844 | self.minDate = [self.calendar dateByAddingComponents:comps toDate:self.maxDate options:NSCalendarMatchLast]; 845 | } 846 | }else 847 | { 848 | self.minDate = [NSDate date]; 849 | } 850 | } 851 | return self.minDate; 852 | } 853 | 854 | /** 855 | * 获取最小时间 856 | */ 857 | -(NSDate*)getMaxDate 858 | { 859 | if (self.maxDate ==nil) { 860 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//同一年 861 | NSDateComponents *addComps = [[NSDateComponents alloc] init]; 862 | addComps.year = 1; 863 | addComps.day = -1; 864 | _maxDate = [self.calendar dateByAddingComponents:addComps toDate:[self getMinDate] options:NSCalendarMatchLast]; 865 | }else if (self.pickerMode==JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//同一天 866 | { 867 | _maxDate = [self getDayLastDateWithDate:self.minDate max:YES]; 868 | } 869 | else{ 870 | NSDateComponents* comps = [[NSDateComponents alloc] init]; 871 | comps.year = 1; 872 | _maxDate = [self.calendar dateByAddingComponents:comps toDate:[self getMinDate] options:NSCalendarMatchLast]; 873 | } 874 | } 875 | return self.maxDate; 876 | } 877 | 878 | /** 879 | * 获取当前时间 880 | */ 881 | -(NSDate*)getCurrentDate 882 | { 883 | if (self.date ==nil) { 884 | self.date = [self getMinDate]; 885 | } 886 | return self.date; 887 | } 888 | 889 | 890 | 891 | /** 892 | * 切换模式时刷新 893 | */ 894 | -(void)setPickerMode:(JWDatePickerMode)pickerMode 895 | { 896 | 897 | _pickerMode = pickerMode; 898 | 899 | 900 | [self setDateFDateFormatter]; 901 | 902 | //年 月 日 单选 903 | if(self.pickerMode==JWDatePickerMode_Date||self.pickerMode==JWDatePickerMode_DateAddHour){ 904 | if (!self.date) { 905 | self.date = [self getMinDate]; 906 | } 907 | NSDateComponents *comps= [self.calendar components:KComUnit fromDate:self.date]; 908 | self.tempDateComps.year=comps.year; 909 | self.tempDateComps.month = comps.month; 910 | } 911 | 912 | if (self.minDate&&self.maxDate) { 913 | if (self.pickerMode==JWDatePickerMode_DateAndTimeRYear||self.pickerMode==JWDatePickerMode_DateAndTimeRYearAndSecond) {//同一年 914 | // 最小时间1年后的时间 compare 最大时间 915 | NSDateComponents *addComps = [[NSDateComponents alloc] init]; 916 | addComps.year = 1; 917 | addComps.day = -1; 918 | NSDate* lastMaxDate = [self.calendar dateByAddingComponents:addComps toDate:self.minDate options:NSCalendarMatchLast]; 919 | if ([lastMaxDate compare:self.maxDate]==NSOrderedAscending) { 920 | 921 | self.maxDate = lastMaxDate; 922 | [self.pickerView reloadAllComponents]; 923 | } 924 | }else if (self.pickerMode==JWDatePickerMode_Time||self.pickerMode==JWDatePickerMode_TimeRSecond)//同一天 925 | { 926 | NSDate* lastMaxDate = [self getDayLastDateWithDate:self.minDate max:YES]; 927 | 928 | if ([lastMaxDate compare:self.maxDate]==NSOrderedAscending) { 929 | self.maxDate = lastMaxDate; 930 | [self.pickerView reloadAllComponents]; 931 | } 932 | } 933 | } 934 | 935 | [self reloadDataNeedScrollTo:YES]; 936 | 937 | } 938 | 939 | /** 940 | * 设置代理是刷新 941 | */ 942 | -(void)setDelegate:(id)delegate 943 | { 944 | if (delegate) { 945 | _delegate = delegate; 946 | 947 | [self setDateFDateFormatter]; 948 | 949 | [self reloadData]; 950 | } 951 | } 952 | 953 | /** 954 | * 用于转换 选择的时间 955 | */ 956 | -(NSDateFormatter *)simpleDateF 957 | { 958 | if (_simpleDateF==nil) { 959 | _simpleDateF = [[NSDateFormatter alloc] init]; 960 | } 961 | return _simpleDateF; 962 | } 963 | 964 | 965 | /** 966 | * 限制间隔 967 | */ 968 | -(void)setMinuteSpace:(NSUInteger)minuteSpace 969 | { 970 | if (minuteSpace<30&&60%minuteSpace==0) { 971 | _minuteSpace = minuteSpace; 972 | } 973 | 974 | } 975 | 976 | /** 977 | * 限制间隔 978 | */ 979 | -(void)setSecondSpace:(NSUInteger)secondSpace 980 | { 981 | if (secondSpace<30&&60%secondSpace==0) { 982 | _secondSpace = secondSpace; 983 | } 984 | } 985 | 986 | 987 | /** 988 | * 是否是闰年 989 | */ 990 | -(BOOL)isLeapYear:(NSInteger)year 991 | { 992 | if (year%4==0) { 993 | if (year%100==0) { 994 | if (year%400==0) { 995 | return YES; 996 | } 997 | //能被 4 100 整除 不能被400 整除的 不是闰年 998 | return NO; 999 | } 1000 | //能被4整除 不能被100整除的 是闰年 1001 | return YES; 1002 | } 1003 | //不能为4整除 不是闰年 1004 | return NO; 1005 | } 1006 | 1007 | /** 1008 | * 根据对应的年 和月 返回当月对应的天数 1009 | */ 1010 | -(NSInteger)getMonthDaysWithYear:(NSInteger)year andMoth:(NSInteger)moth 1011 | { 1012 | // 31 28 31 30 31 30 31 31 30 31 30 31 1013 | NSArray *daysOfMonth=@[@31,@28,@31,@30,@31,@30,@31,@31,@30,@31,@30,@31]; 1014 | 1015 | NSUInteger days=[daysOfMonth[moth-1] integerValue]; 1016 | 1017 | if (days==28) { 1018 | if ([self isLeapYear:year])days=29; 1019 | } 1020 | return days; 1021 | } 1022 | 1023 | -(NSDateComponents *)tempDateComps 1024 | { 1025 | if (_tempDateComps==nil) { 1026 | _tempDateComps = [[NSDateComponents alloc] init]; 1027 | } 1028 | return _tempDateComps; 1029 | } 1030 | 1031 | 1032 | -(NSString *)getDateStrWithDateFormatterString:(NSString *)formatterStr 1033 | { 1034 | if (self.date&&formatterStr&&formatterStr.length) { 1035 | 1036 | } 1037 | return @"格式化字符串不合法"; 1038 | } 1039 | 1040 | -(NSString *)getDateStr 1041 | { 1042 | if (self.date) { 1043 | return [[self.simpleDateF stringFromDate:self.date] stringByReplacingOccurrencesOfString:KSplit withString:@""]; 1044 | } 1045 | return @"NO Date"; 1046 | } 1047 | 1048 | /** 1049 | * 获取一天中的 最小时间 最大时间 1050 | */ 1051 | -(NSDate*)getDayLastDateWithDate:(NSDate*)date max:(BOOL)isGetMax 1052 | { 1053 | if (!date) { 1054 | return [NSDate date]; 1055 | } 1056 | 1057 | NSDateComponents*dateComps = [self.calendar components:KComUnit fromDate:date]; 1058 | NSInteger hour = dateComps.hour; 1059 | NSInteger minute = dateComps.minute; 1060 | NSInteger second = dateComps.second; 1061 | 1062 | NSDateComponents *newDateComp = [NSDateComponents new]; 1063 | if (isGetMax) { 1064 | newDateComp.hour = 24-hour-1; 1065 | newDateComp.minute = 60 - minute -1; 1066 | newDateComp.second = 60 - second -1; 1067 | }else 1068 | { 1069 | newDateComp.hour = -hour; 1070 | newDateComp.minute = -minute; 1071 | newDateComp.second = -second; 1072 | } 1073 | NSDate* lastDate = [self.calendar dateByAddingComponents:newDateComp toDate:date options:NSCalendarMatchLast]; 1074 | return lastDate; 1075 | } 1076 | @end 1077 | -------------------------------------------------------------------------------- /JWDatePickerView-Swift/JWDatePickerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JWDatePickerView.swift 3 | // CarServer 4 | // 5 | // Created by 朱建伟 on 2016/10/13. 6 | // Copyright © 2016年 zhujianwei. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /* 12 | 13 | 使用方法 14 | pickerMode:JWDatePickerMode? 日期选择模式 15 | minDate:Date? 最小日期 16 | maxDate:Date? 最大日期 17 | date:Date? 当前日期 18 | enableLimited:Bool? 限制滚动区域模式 开启后最大最小日期至少有一个有值时有效 19 | unitStrClosure:((NSCalendar.Unit)-> String)? 获取单位的闭包 例如:年 月 日 时 分 秒 20 | didSelectedDateClosure:((Date)->())? 选中了日期 21 | */ 22 | 23 | /* 24 | 时间控件的模式 25 | */ 26 | public enum JWDatePickerMode:Int{ 27 | 28 | case dateAndTime// 年月日 时 分 秒 29 | case dateAndHour// 年月日 时 30 | case dateAndTimeRYear// 月日 时 分 秒 31 | case time// 时 分 秒 32 | case timeRSecond// 时 分 33 | case date// 年 月 日 34 | case dateAddHour// 年 月 日 时 35 | case dateAndTimeRSecond// 年月日 时 分 36 | case dateAndTimeRYearAndSecond// 月日 时 分 3 37 | case dateAndTimeForAllComponent// 年 月 日 时 分 秒 38 | } 39 | 40 | 41 | //Unit 42 | let UnitYear:NSCalendar.Unit = [.year] 43 | let UnitMonth:NSCalendar.Unit = [.month] 44 | let UnitDay:NSCalendar.Unit = [.day] 45 | let UnitHour:NSCalendar.Unit = [.hour] 46 | let UnitMinute:NSCalendar.Unit = [.minute] 47 | let UnitSecond:NSCalendar.Unit = [.second] 48 | let Option:NSCalendar.Options = NSCalendar.Options(rawValue: 0) 49 | 50 | 51 | class JWDatePickerView: UIView,UIPickerViewDelegate,UIPickerViewDataSource{ 52 | 53 | 54 | //MARK:公有方法 和 公有属性 55 | 56 | //获取单位 57 | var unitStrClosure:((NSCalendar.Unit)-> String)? 58 | 59 | //选中日期 60 | var didSelectedDateClosure:((Date)->())? 61 | 62 | //无限滚动的最大范围 63 | private let MaxRangeValue:Int = 88888 64 | 65 | //记录当日期选择模式中 无限滚动选项的当前日期 对应组选项索引 66 | private var currentIndex:Int? 67 | 68 | //是否正在滚动 69 | private var currentOperationComponent:Int = 0 70 | 71 | /** 72 | * 最小日期 73 | */ 74 | private var _minDate:Date? 75 | var minDate:Date?{ 76 | set{ 77 | 78 | if let minD = newValue{ 79 | _minDate = newValue 80 | //设置最大日期 如果最小日期比最大日期还要大 81 | if let tempMaxDate = maxDate{ 82 | //最小日期 比最大日期大 83 | if minD.compare(tempMaxDate) == ComparisonResult.orderedDescending{ 84 | //设置最大日期为最小日期 85 | _maxDate = minD 86 | }else{ 87 | //如果是需要限制在短时间内的 88 | let unitSubArray:[UInt] = (pickerModeDict[pickerMode!]?.first!)! 89 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{ 90 | let destinationDate = getDateAddOrReduceYear(date: minD, isAdd: true) 91 | 92 | //如果最大日期超过最小日期一年后的范围 93 | if tempMaxDate.compare(destinationDate) == ComparisonResult.orderedDescending{ 94 | _maxDate = destinationDate 95 | } 96 | } 97 | } 98 | }else{//最大日期没有值,如果模式需要限制在一年内 99 | let unitSubArray:[UInt] = (pickerModeDict[pickerMode!]?.first!)! 100 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{ 101 | 102 | //一年后的日期 103 | let destinationDate:Date = self.getDateAddOrReduceYear(date: minD, isAdd: true) 104 | //修改掉 105 | _maxDate = destinationDate 106 | } 107 | } 108 | 109 | //验证当前日期 110 | if let currentDate = self.date{ 111 | //判断当前日期是否在范围内 112 | 113 | //当前时间比最小时间 114 | if currentDate.compare(minD) == ComparisonResult.orderedAscending{ 115 | _date = minD 116 | } 117 | 118 | //判断最大日期的范围 119 | if let tempMaxDate = maxDate{ 120 | if currentDate.compare(tempMaxDate) == ComparisonResult.orderedDescending{//当前时间比最大时间大 121 | _date = tempMaxDate 122 | } 123 | } 124 | }else{ 125 | _date = minD 126 | } 127 | 128 | //刷新 129 | toCurentDate(animated: false) 130 | }else 131 | { 132 | _minDate = newValue 133 | 134 | //刷新 135 | toCurentDate(animated: false) 136 | } 137 | } 138 | get{ 139 | 140 | if _minDate == nil { 141 | 142 | let unitSubArray:[UInt] = (pickerModeDict[pickerMode!]?.first!)! 143 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{ 144 | 145 | //如果最大日期有值 146 | if let tempMaxDate = _maxDate{ 147 | let destinationDate = getDateAddOrReduceYear(date: tempMaxDate, isAdd: false) 148 | 149 | //设置时间 150 | self.minDate = destinationDate 151 | }else{ 152 | if let date = self.date{ 153 | //判断最小日期是否在一年的范围内 154 | var addComps:DateComponents = DateComponents() 155 | 156 | //闰年 157 | if self.isLeapYear(year: (self.currentDateCompnents?.year)!){ 158 | addComps.day = -((366-1)/2) 159 | }else{ 160 | addComps.day = -((365-1)/2) 161 | } 162 | 163 | //日期 164 | let lastDate:Date = calendar.date(byAdding: addComps, to:date, options: NSCalendar.Options.matchLast)! 165 | 166 | _minDate = lastDate 167 | } 168 | } 169 | } 170 | } 171 | 172 | return _minDate 173 | } 174 | } 175 | 176 | 177 | /** 178 | * 最大日期 179 | */ 180 | private var _maxDate:Date? 181 | var maxDate:Date? 182 | { 183 | set{ 184 | if let maxD = newValue{ 185 | _maxDate = maxD 186 | //设置最小日期 如果最大日期比最小日期还要小 187 | if let tempMinDate = minDate{ 188 | //最大日期 比最小日期小 189 | if maxD.compare(tempMinDate) == ComparisonResult.orderedAscending{ 190 | //设置最小日期为最大日期 191 | _minDate = maxD 192 | }else{ 193 | //如果是需要限制在短时间内的 194 | let unitSubArray:[UInt] = (pickerModeDict[pickerMode!]?.first!)! 195 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{ 196 | let destinationDate = getDateAddOrReduceYear(date: maxD, isAdd: false) 197 | 198 | //如果最小日期超过最大日期一年后的范围 199 | if tempMinDate.compare(destinationDate) == ComparisonResult.orderedAscending{ 200 | _minDate = destinationDate 201 | } 202 | } 203 | } 204 | }else{//最大日期没有值,如果模式需要限制在一年内 205 | let unitSubArray:[UInt] = (pickerModeDict[pickerMode!]?.first!)! 206 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{ 207 | 208 | //一年后的日期 209 | let destinationDate:Date = self.getDateAddOrReduceYear(date: maxD, isAdd: false) 210 | //修改掉 211 | _minDate = destinationDate 212 | } 213 | } 214 | 215 | //验证当前日期 216 | if let currentDate = self.date{ 217 | //判断当前日期是否在范围内 218 | 219 | if let tempMinDate = minDate{ 220 | //当前时间比最小时间 221 | if currentDate.compare(tempMinDate) == ComparisonResult.orderedAscending{ 222 | _date = tempMinDate 223 | } 224 | } 225 | 226 | //判断最大日期的范围 227 | if currentDate.compare(maxD) == ComparisonResult.orderedDescending{//当前时间比最大时间大 228 | _date = maxD 229 | } 230 | }else{ 231 | _date = maxD 232 | } 233 | 234 | 235 | //刷新 236 | toCurentDate(animated: false) 237 | }else 238 | { 239 | _maxDate = newValue 240 | 241 | //刷新 242 | toCurentDate(animated: false) 243 | } 244 | 245 | } 246 | get{ 247 | if _maxDate == nil { 248 | let unitSubArray:[UInt] = (pickerModeDict[pickerMode!]?.first!)! 249 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{ 250 | 251 | //如果最大日期有值 252 | if let tempMinDate = _minDate{ 253 | let destinationDate = getDateAddOrReduceYear(date: tempMinDate, isAdd: true) 254 | 255 | //设置时间 256 | self.maxDate = destinationDate 257 | }else{ 258 | if let date = self.date{ 259 | //判断最小日期是否在一年的范围内 260 | var addComps:DateComponents = DateComponents() 261 | 262 | //闰年 263 | if self.isLeapYear(year: (self.currentDateCompnents?.year)!){ 264 | addComps.day = (366-1)/2 265 | }else{ 266 | addComps.day = (365-1)/2 267 | } 268 | 269 | //日期 270 | let lastDate:Date = calendar.date(byAdding: addComps, to:date, options: NSCalendar.Options.matchLast)! 271 | 272 | _maxDate = lastDate 273 | } 274 | } 275 | 276 | 277 | } 278 | } 279 | 280 | return _maxDate 281 | } 282 | } 283 | 284 | /** 285 | * 当前日期 286 | */ 287 | private var _date:Date? 288 | var date:Date? 289 | { 290 | set{ 291 | if let d = newValue { 292 | if let tempMinD = minDate{ 293 | if d.compare(tempMinD) == ComparisonResult.orderedAscending{ 294 | print("指定日期不在范围内") 295 | return 296 | } 297 | } 298 | if let tempMaxD = maxDate 299 | { 300 | if d.compare(tempMaxD) == ComparisonResult.orderedDescending{ 301 | print("指定日期不在范围内") 302 | return 303 | } 304 | } 305 | 306 | 307 | //设置当前的comps 308 | currentDateCompnents = calendar.components(ComUnit, from: d) 309 | _date = d 310 | 311 | toCurentDate(animated: false) 312 | 313 | //刷新 314 | pickerView.reloadAllComponents() 315 | }else 316 | { 317 | _date = newValue 318 | 319 | pickerView .reloadAllComponents() 320 | } 321 | } 322 | get{ 323 | if let d = _date 324 | { 325 | return d 326 | }else 327 | { 328 | _date = Date() 329 | 330 | //设置当前的comps 331 | currentDateCompnents = calendar.components(ComUnit, from: _date!) 332 | 333 | return _date 334 | } 335 | } 336 | } 337 | 338 | 339 | //单位 340 | private var _unitDescDict:[UInt:String]! 341 | private var unitDescDict:[UInt:String]!{ 342 | set{ 343 | if let dict = newValue { 344 | _unitDescDict = dict 345 | } 346 | } 347 | get{ 348 | if _unitDescDict == nil { 349 | _unitDescDict = [UInt:String]() 350 | _unitDescDict[UnitYear.rawValue] = "年" 351 | _unitDescDict[UnitMonth.rawValue] = "月" 352 | _unitDescDict[UnitDay.rawValue] = "日" 353 | _unitDescDict[UnitHour.rawValue] = "时" 354 | _unitDescDict[UnitMinute.rawValue] = "分" 355 | _unitDescDict[UnitSecond.rawValue] = "秒" 356 | } 357 | 358 | return _unitDescDict 359 | } 360 | } 361 | 362 | /** 363 | * pickerModel 364 | */ 365 | private var _pickerMode:JWDatePickerMode? 366 | var pickerMode:JWDatePickerMode?{ 367 | get{ 368 | if _pickerMode == nil 369 | { 370 | _pickerMode = JWDatePickerMode.dateAndTimeForAllComponent 371 | 372 | } 373 | 374 | return _pickerMode 375 | } 376 | set{ 377 | if let mode = newValue { 378 | _pickerMode = mode 379 | 380 | pickerView.reloadAllComponents() 381 | 382 | //切换模式必须滚动到指定 383 | toCurentDate(animated: false) 384 | } 385 | } 386 | } 387 | 388 | //用来记录 当前选中的年月 389 | private var tempDateCompnents:DateComponents = DateComponents() 390 | 391 | 392 | //用来记录当前date 的 DateComponents 393 | private var _currentDateCompnents:DateComponents? 394 | var currentDateCompnents:DateComponents?{ 395 | set{ 396 | if let comps = newValue 397 | { 398 | _currentDateCompnents = comps 399 | }else 400 | { 401 | _currentDateCompnents = newValue//可能为nil 402 | } 403 | } 404 | get { 405 | 406 | //如果等于 nil 去获取 407 | if _currentDateCompnents == nil { 408 | //设置当前的comps 409 | _currentDateCompnents = calendar.components(ComUnit, from: date!) 410 | } 411 | return _currentDateCompnents 412 | } 413 | } 414 | 415 | //滚动到指定的日期 416 | func scrollToDate(date:Date?,animated:Bool) 417 | { 418 | 419 | if let d = date { 420 | //赋值私有属性 421 | _date = d 422 | 423 | //设置当前的comps 424 | currentDateCompnents = calendar.components(ComUnit, from: d) 425 | 426 | toCurentDate(animated: animated) 427 | } 428 | } 429 | 430 | 431 | /** 432 | * 是否是闰年 433 | */ 434 | func isLeapYear(year:Int) -> Bool { 435 | if (year%4==0) { 436 | if (year%100==0) { 437 | if (year%400==0) { 438 | return true 439 | } 440 | //能被 4 100 整除 不能被400 整除的 不是闰年 441 | return false 442 | } 443 | //能被4整除 不能被100整除的 是闰年 444 | return true 445 | } 446 | //不能为4整除 不是闰年 447 | return false 448 | 449 | } 450 | 451 | /** 452 | * 根据对应的年 和月 返回当月对应的天数 453 | */ 454 | func numberOfDaysInMonth(year:Int,month:Int) -> Int { 455 | // 31 28 31 30 31 30 31 31 30 31 30 31 456 | let daysOfMonth:[Int] = [31,28,31,30,31,30,31,31,30,31,30,31] 457 | 458 | let index:Int = (month - 1) 459 | var days:Int = daysOfMonth[index] 460 | 461 | if (days == 28) { 462 | if (isLeapYear(year: year)){ 463 | days = 29 464 | } 465 | } 466 | return days 467 | 468 | } 469 | 470 | /** 471 | * 获取一天中的 最小时间 最大时间 472 | */ 473 | func dayFirstOrLastDate(date:Date,isLast:Bool) -> Date { 474 | let dateComps:DateComponents = calendar.components(ComUnit, from: date) 475 | let hour:Int = dateComps.hour! 476 | let minute:Int = dateComps.minute! 477 | let second:Int = dateComps.second! 478 | 479 | var newDateComps:DateComponents = DateComponents() 480 | if (isLast) { 481 | newDateComps.hour = 24 - hour - 1; 482 | newDateComps.minute = 60 - minute - 1 483 | newDateComps.second = 60 - second - 1 484 | }else 485 | { 486 | newDateComps.hour = -hour; 487 | newDateComps.minute = -minute; 488 | newDateComps.second = -second; 489 | } 490 | 491 | let d:Date = calendar.date(byAdding: newDateComps, to: date, options: NSCalendar.Options.matchLast)! 492 | return d 493 | 494 | } 495 | 496 | 497 | 498 | //MARK:私有属性 499 | 500 | //开启后 如果 最大日期 或者 最小日期有值 则单向或者双向有限制 否则无效 默认不开启限制 501 | private var _enableLimited:Bool? 502 | var enableLimited:Bool?{ 503 | set{ 504 | if let enable = newValue{ 505 | _enableLimited = enable 506 | 507 | pickerView.reloadAllComponents() 508 | 509 | //刷新时间 510 | toCurentDate(animated: true) 511 | } 512 | } 513 | get{ 514 | if let enable = _enableLimited{ 515 | return enable 516 | }else 517 | { 518 | return false 519 | } 520 | } 521 | } 522 | 523 | 524 | //comUnit 525 | private let ComUnit:NSCalendar.Unit = [.year,.day,.month,.hour,.minute,.second] 526 | 527 | //记录 当前日期选中 528 | private var sourceCompnentRowDict:[Int:Int] = [Int:Int]() 529 | 530 | //Calendar 531 | private let calendar:NSCalendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!//NSCalendar(identifier: Calendar.Identifier.gregorian) 532 | 533 | //MARK:控件 534 | 535 | /** 536 | * pickerView 537 | */ 538 | private var pickerView:UIPickerView = UIPickerView() 539 | 540 | 541 | //日期选择控件模式 542 | private var pickerModeDict:[JWDatePickerMode:[[UInt]]] = { 543 | var pickerMode:[JWDatePickerMode:[[UInt]]] = [JWDatePickerMode:[[UInt]]]() 544 | 545 | // 年月日 时 分 秒 546 | pickerMode[.dateAndTime] = [[UnitYear.rawValue,UnitMonth.rawValue,UnitDay.rawValue],[UnitHour.rawValue],[UnitMinute.rawValue],[UnitSecond.rawValue]] 547 | 548 | // 月日 时 分 秒 549 | pickerMode[.dateAndTimeRYear] = [[UnitMonth.rawValue,UnitDay.rawValue],[UnitHour.rawValue],[UnitMinute.rawValue],[UnitSecond.rawValue]] 550 | 551 | // 年月日 时 552 | pickerMode[.dateAndHour] = [[UnitYear.rawValue,UnitMonth.rawValue,UnitDay.rawValue],[UnitHour.rawValue]] 553 | 554 | 555 | // 时分秒 556 | pickerMode[.time] = [[UnitHour.rawValue],[UnitMinute.rawValue],[UnitSecond.rawValue]] 557 | 558 | //时分 559 | pickerMode[.timeRSecond] = [[UnitHour.rawValue],[UnitMinute.rawValue]] 560 | 561 | // 年月日 562 | pickerMode[.date] = [[UnitYear.rawValue],[UnitMonth.rawValue],[UnitDay.rawValue]] 563 | 564 | // 年 月 日 时 565 | pickerMode[.dateAddHour] = [[UnitYear.rawValue,UnitMonth.rawValue,UnitDay.rawValue],[UnitHour.rawValue]] 566 | 567 | // 年月日 时 分 568 | pickerMode[.dateAndTimeRSecond] = [[UnitYear.rawValue,UnitMonth.rawValue,UnitDay.rawValue],[UnitHour.rawValue],[UnitMinute.rawValue]] 569 | 570 | //月日 时 分 571 | pickerMode[.dateAndTimeRYearAndSecond] = [[UnitMonth.rawValue,UnitDay.rawValue],[UnitHour.rawValue],[UnitMinute.rawValue],[UnitSecond.rawValue]] 572 | 573 | //年 月 日 时 分 秒 574 | pickerMode[.dateAndTimeForAllComponent] = [[UnitYear.rawValue],[UnitMonth.rawValue],[UnitDay.rawValue],[UnitHour.rawValue],[UnitMinute.rawValue],[UnitSecond.rawValue]] 575 | 576 | return pickerMode 577 | }() 578 | 579 | //初始化 580 | override init(frame: CGRect) { 581 | super.init(frame: frame) 582 | 583 | addSubview(pickerView) 584 | 585 | currentIndex = MaxRangeValue/2 586 | 587 | pickerView.dataSource = self 588 | 589 | //跳到当前日期 590 | toCurentDate(animated: false) 591 | 592 | pickerView.delegate = self 593 | 594 | } 595 | 596 | required init?(coder aDecoder: NSCoder) { 597 | fatalError("init(coder:) has not been implemented") 598 | } 599 | 600 | 601 | //MARK:pickerView代理和数据源 602 | internal func numberOfComponents(in pickerView: UIPickerView) -> Int { 603 | 604 | //1.获取当前模式 605 | let unitArray:[[UInt]] = pickerModeDict[pickerMode!]! 606 | 607 | //2.返回该模式下的components 608 | return unitArray.count 609 | } 610 | 611 | 612 | internal func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 613 | //1.获取当前模式 614 | let unitArray:[[UInt]] = pickerModeDict[pickerMode!]! 615 | //2.判断类型 616 | 617 | var rows = 1 618 | 619 | let unitSubArray:[UInt] = unitArray[component] 620 | 621 | let unit:UInt = unitSubArray.last! 622 | 623 | //3.分类型处理 624 | switch unit { 625 | case UnitYear.rawValue: 626 | //判断限制模式 627 | if limitedEnable() { 628 | //开启了限制返回数据源 629 | rows = numberOfRowsInComponetForLimited(component: component,unit: unit) 630 | }else 631 | { 632 | rows = MaxRangeValue 633 | } 634 | break 635 | case UnitMonth.rawValue: 636 | //判断限制模式 637 | if limitedEnable() { 638 | //开启了限制返回数据源 639 | rows = numberOfRowsInComponetForLimited(component: component,unit: unit) 640 | }else{ 641 | //默认12 642 | rows = 12 643 | //第一组的最后一个是 month 644 | if component == 0 { 645 | rows = MaxRangeValue 646 | } 647 | } 648 | break 649 | case UnitDay.rawValue: 650 | //判断限制模式 651 | if limitedEnable() { 652 | //开启了限制返回数据源 653 | rows = numberOfRowsInComponetForLimited(component: component,unit: unit) 654 | }else{ 655 | //第一组的最后一个是 days 656 | if component == 0 { 657 | rows = MaxRangeValue 658 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{//如果第一个是月份 659 | if isLeapYear(year: (currentDateCompnents?.year)!) { 660 | rows = 366-1 661 | }else{ 662 | rows = 355-1 663 | } 664 | } 665 | }else//不是第一组 说明需要考虑 选完月份后 该月的天数问题 666 | { 667 | rows = numberOfDaysInMonth(year:tempDateCompnents.year!, month: tempDateCompnents.month!) 668 | } 669 | } 670 | break 671 | case UnitHour.rawValue: 672 | rows = 24//无论是否开启 数据源 公用 673 | break 674 | case UnitMinute.rawValue: 675 | rows = 60 676 | break 677 | case UnitSecond.rawValue: 678 | rows = 60 679 | break 680 | default: 681 | 682 | break 683 | } 684 | return rows 685 | } 686 | 687 | 688 | //获取标题 689 | internal func pickerViewTitle(forRow row:Int,forComponent component:Int) -> String { 690 | 691 | self.currentOperationComponent = component 692 | 693 | //1.计算增量 694 | var addComps:DateComponents = DateComponents() 695 | 696 | //2.获取当前模式 697 | let unitArray:[[UInt]] = pickerModeDict[pickerMode!]! 698 | let unitSubArray:[UInt] = unitArray[component] 699 | let unit:UInt = unitSubArray.last! 700 | 701 | 702 | //3.判断是否第一组 703 | if component == 0 { 704 | //计算偏差 705 | switch unit { 706 | case UnitYear.rawValue: 707 | addComps.year = row - sourceCompnentRowDict[component]! 708 | break 709 | case UnitMonth.rawValue: 710 | addComps.month = row - sourceCompnentRowDict[component]! 711 | break 712 | case UnitDay.rawValue: 713 | addComps.day = row - sourceCompnentRowDict[component]! 714 | break 715 | default: 716 | //剩下的时分秒 717 | return String(format:"%02zd%@",row,unitDescDict[unit]!) 718 | // break 719 | } 720 | 721 | 722 | let tempDate:Date? = calendar.date(byAdding: addComps, to: date!) 723 | 724 | if let tDate:Date = tempDate { 725 | let dateComps:DateComponents = calendar.components(ComUnit, from: tDate) 726 | 727 | return getTitle(comps: dateComps, component:component) 728 | }else 729 | { 730 | return "title nil" 731 | } 732 | }else 733 | { 734 | if unit == UnitMonth.rawValue || unit == UnitDay.rawValue{ 735 | return String(format:"%02zd%@",row+1,unitDescDict[unit]!) 736 | }else{ 737 | return String(format:"%02zd%@",row,unitDescDict[unit]!) 738 | } 739 | 740 | } 741 | } 742 | 743 | 744 | 745 | internal func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat { 746 | //1.获取当前模式 747 | let unitArray:[[UInt]] = pickerModeDict[pickerMode!]! 748 | 749 | //2.计算全部的个数 750 | var totalCount:Int = 0 751 | var totalComponentCount:Int = 0 752 | 753 | var tempComponent = 0 754 | for unitSubArray:[UInt] in unitArray{ 755 | for unit:UInt in unitSubArray { 756 | var add:Int = (1 + ( unitDescDict[unit]?.characters.count)!) 757 | // 年的话,加位 758 | if unit == UnitYear.rawValue { 759 | add += 1 760 | } 761 | //计算总长 762 | totalCount += add 763 | //计算当前 764 | if tempComponent == component { 765 | totalComponentCount += add 766 | } 767 | } 768 | tempComponent += 1 769 | } 770 | 771 | //3.更合理的划分 772 | let width:CGFloat = (pickerView.bounds.width - 20.0) 773 | let baseWidth:CGFloat = width/CGFloat(unitArray.count) 774 | let mutiWidth:CGFloat = width - baseWidth 775 | 776 | //4.计算宽度 777 | let componentWidth:CGFloat = CGFloat(totalComponentCount)/CGFloat(totalCount)*mutiWidth + (baseWidth/CGFloat(unitArray.count)) 778 | 779 | return componentWidth 780 | 781 | } 782 | 783 | //返回选项高度 784 | internal func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { 785 | return pickerView.bounds.height/5 786 | } 787 | 788 | 789 | //返回label 790 | internal func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { 791 | 792 | let title:String = pickerViewTitle(forRow: row, forComponent: component) 793 | 794 | var label:UILabel? = nil 795 | 796 | if view != nil { 797 | label = view as! UILabel? 798 | }else{ 799 | label = UILabel() 800 | label?.textAlignment = NSTextAlignment.center 801 | // Font_120_218_317_416_515_614_712_810_908 802 | label?.font = Font4 803 | label?.text = title 804 | } 805 | return label! 806 | } 807 | 808 | 809 | //选择停止 810 | func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 811 | 812 | //优化掉 813 | if self.currentOperationComponent != component{ 814 | return 815 | } 816 | 817 | //1.获取当前模式 818 | let unitArray:[[UInt]] = pickerModeDict[pickerMode!]! 819 | 820 | //2.遍历 每一组最后一个 821 | var tempComponent:Int = 0 822 | 823 | //用来加减 824 | var addDateComps:DateComponents = DateComponents() 825 | 826 | for unitSubArray:[UInt] in unitArray 827 | { 828 | //当前选中 829 | var currentRow:Int = pickerView.selectedRow(inComponent: tempComponent) 830 | if component == tempComponent { 831 | currentRow = row 832 | } 833 | //单位 834 | let unit:UInt = unitSubArray.last! 835 | 836 | 837 | //分类型处理 838 | switch unit { 839 | case UnitYear.rawValue: 840 | addDateComps.year = currentRow - sourceCompnentRowDict[tempComponent]! 841 | break 842 | case UnitMonth.rawValue: 843 | addDateComps.month = currentRow - sourceCompnentRowDict[tempComponent]! 844 | break 845 | case UnitDay.rawValue: 846 | //如果不是第一组才需要验证 847 | if tempComponent != 0 { 848 | //验证日期 因为每一月的天数不一样 849 | //1.第一步先计算当前步骤选中的年月 850 | let tempDate:Date? = calendar.date(byAdding: addDateComps, to: self.date!, options: NSCalendar.Options.matchLast) 851 | let tempDateComps:DateComponents = calendar.components(ComUnit, from: tempDate!) 852 | tempDateCompnents.year = tempDateComps.year 853 | tempDateCompnents.month = tempDateComps.month 854 | //2.获取天数 855 | let days:Int = numberOfDaysInMonth(year: tempDateComps.year!, month: tempDateComps.month!) 856 | //3.判断当前选择项是否越界 857 | if currentRow > days - 1 {//假如目前为 12月 则 31天 索引 30 ,当选择至11月 则 30天 索引 29 若日期为 12月31 则选择回11月30,最大索引变为29 但当前索引为30 则会越界 858 | 859 | //先选回29再刷新 防止越界闪退 860 | pickerView.selectRow(days - 1, inComponent: tempComponent, animated: false) 861 | 862 | //更新掉 sourceCompentRowDict 和 currentRow 863 | currentRow = days - 1 864 | } 865 | //刷新月份coponent 不同的月份天数不同 随时更新 866 | pickerView.reloadComponent(tempComponent) 867 | } 868 | 869 | //计算时间 870 | addDateComps.day = currentRow - sourceCompnentRowDict[tempComponent]! 871 | break 872 | case UnitHour.rawValue: 873 | addDateComps.hour = currentRow - sourceCompnentRowDict[tempComponent]! 874 | break 875 | case UnitMinute.rawValue: 876 | addDateComps.minute = currentRow - sourceCompnentRowDict[tempComponent]! 877 | break 878 | case UnitSecond.rawValue: 879 | addDateComps.second = currentRow - sourceCompnentRowDict[tempComponent]! 880 | break 881 | default: 882 | 883 | break 884 | } 885 | tempComponent += 1 886 | } 887 | 888 | let date:Date? = calendar.date(byAdding: addDateComps, to: self.date!, options: NSCalendar.Options.matchLast) 889 | if let d = date { 890 | 891 | //标记 892 | var compareFlag:Bool = true 893 | 894 | //如果存在最小的时间 895 | if let minD:Date = minDate { 896 | //当前日期小于最小日期 897 | if(d.compare(minD) == ComparisonResult.orderedAscending){ 898 | if let closure = didSelectedDateClosure 899 | { 900 | closure(minD) 901 | } 902 | scrollToDate(date: minD, animated: true) 903 | compareFlag = false 904 | } 905 | } 906 | 907 | //如果存在最大时间 908 | if let maxD:Date = maxDate { 909 | //当前日期大于当前日期 910 | if(d.compare(maxD) == ComparisonResult.orderedDescending){ 911 | if let closure = didSelectedDateClosure 912 | { 913 | closure(maxD) 914 | } 915 | scrollToDate(date: maxD, animated: true) 916 | compareFlag = false 917 | } 918 | } 919 | 920 | //日期已定 921 | if compareFlag 922 | { 923 | //如果未开启限制模式,则自动滚动 无限滚动 924 | 925 | scrollToDate(date: d, animated: false) 926 | if let closure = didSelectedDateClosure 927 | { 928 | closure(d) 929 | } 930 | } 931 | } 932 | } 933 | 934 | 935 | //滚动到指定页 936 | internal func toCurentDate(animated:Bool) { 937 | 938 | tempDateCompnents.year = currentDateCompnents?.year 939 | tempDateCompnents.month = currentDateCompnents?.month 940 | 941 | //1.获取当前模式 942 | let unitArray:[[UInt]] = pickerModeDict[pickerMode!]! 943 | 944 | //2.设置选中 945 | var comps:DateComponents = currentDateCompnents! 946 | 947 | //3.分类型处理 948 | var component:Int = 0 949 | var tempRow:Int = 0 950 | for unitSubArray:[UInt] in unitArray{ 951 | let unit:UInt = unitSubArray.last! 952 | 953 | switch unit { 954 | case UnitYear.rawValue: 955 | //判断限制模式 956 | if limitedEnable() { 957 | //开启了限制返回数据源 958 | tempRow = selectedRowInComponentForLimited(component: component, unit: unit) 959 | }else{ 960 | //第一组的最后一个是 year 961 | tempRow = currentIndex! 962 | } 963 | break 964 | case UnitMonth.rawValue: 965 | //判断限制模式 966 | if limitedEnable() { 967 | //开启了限制返回数据源 968 | tempRow = selectedRowInComponentForLimited(component: component, unit: unit) 969 | }else{ 970 | if component == 0 { 971 | //第一组的最后一个是 month 972 | tempRow = currentIndex! 973 | }else 974 | { 975 | //指向 month 976 | tempRow = comps.month!-1 977 | } 978 | } 979 | break 980 | case UnitDay.rawValue: 981 | //判断限制模式 982 | if limitedEnable() { 983 | //开启了限制返回数据源 984 | tempRow = selectedRowInComponentForLimited(component: component, unit: unit) 985 | }else{ 986 | if component == 0{ 987 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue {//如果第一个是月份 即不是年 988 | if isLeapYear(year: (currentDateCompnents?.year)!) { 989 | //第一组的最后一个是 Day 990 | tempRow = (366-1)/2-1 991 | }else{ 992 | //第一组的最后一个是 Day 993 | tempRow = (365-1)/2-1 994 | } 995 | }else{ 996 | //第一组的最后一个是 Day 997 | tempRow = currentIndex! 998 | } 999 | }else 1000 | { 1001 | //指向 day 1002 | tempRow = comps.day! - 1 1003 | } 1004 | } 1005 | break 1006 | case UnitHour.rawValue: 1007 | //判断限制模式 1008 | if limitedEnable() { 1009 | //开启了限制返回数据源 1010 | tempRow = selectedRowInComponentForLimited(component: component, unit: unit) 1011 | }else{ 1012 | //指向 hour 1013 | tempRow = comps.hour! 1014 | } 1015 | break 1016 | case UnitMinute.rawValue: 1017 | //判断限制模式 1018 | if limitedEnable() { 1019 | //开启了限制返回数据源 1020 | tempRow = selectedRowInComponentForLimited(component: component, unit: unit) 1021 | }else{ 1022 | //指向 minute 1023 | tempRow = comps.minute! 1024 | } 1025 | break 1026 | case UnitSecond.rawValue: 1027 | //判断限制模式 1028 | if limitedEnable() { 1029 | //开启了限制返回数据源 1030 | tempRow = selectedRowInComponentForLimited(component: component, unit: unit) 1031 | }else{ 1032 | //指向 second 1033 | tempRow = comps.second! 1034 | } 1035 | break 1036 | default: 1037 | // 1038 | break 1039 | } 1040 | 1041 | //滑动到指定选项 1042 | pickerView.selectRow(tempRow, inComponent: component, animated: 1043 | animated) 1044 | //存储 1045 | sourceCompnentRowDict[component] = tempRow 1046 | 1047 | component += 1 1048 | 1049 | 1050 | } 1051 | pickerView.reloadAllComponents() 1052 | } 1053 | 1054 | //布局 1055 | override func layoutSubviews() { 1056 | super.layoutSubviews() 1057 | 1058 | let pickerX:CGFloat = 0 1059 | let pickerY:CGFloat = 0 1060 | let pickerW:CGFloat = bounds.width 1061 | let pickerH:CGFloat = bounds.height 1062 | pickerView.frame = CGRect(x: pickerX, y: pickerY, width: pickerW, height: pickerH) 1063 | } 1064 | 1065 | 1066 | //获取标题 1067 | internal func getTitle(comps:DateComponents,component:Int) -> String 1068 | { 1069 | var m_str:String = String() 1070 | 1071 | //1.获取当前模式 1072 | let unitArray:[[UInt]] = pickerModeDict[pickerMode!]! 1073 | let subArray:[UInt] = unitArray[component] 1074 | 1075 | for unit:UInt in subArray{ 1076 | //分类型处理 1077 | switch unit { 1078 | case UnitYear.rawValue: 1079 | m_str.append(String(format: "%04zd%@", comps.year!,unitDescDict[unit]!)) 1080 | break 1081 | case UnitMonth.rawValue: 1082 | m_str.append(String(format: "%02zd%@", comps.month!,unitDescDict[unit]!)) 1083 | break 1084 | case UnitDay.rawValue: 1085 | m_str.append(String(format: "%02zd%@", comps.day!,unitDescDict[unit]!)) 1086 | break 1087 | case UnitHour.rawValue: 1088 | m_str.append(String(format: "%02zd%@", comps.hour!,unitDescDict[unit]!)) 1089 | break 1090 | case UnitMinute.rawValue: 1091 | m_str.append(String(format: "%02zd%@", comps.minute!,unitDescDict[unit]!)) 1092 | break 1093 | case UnitSecond.rawValue: 1094 | m_str.append(String(format: "%02zd%@", comps.second!,unitDescDict[unit]!)) 1095 | break 1096 | default: 1097 | 1098 | break 1099 | } 1100 | } 1101 | return m_str 1102 | } 1103 | 1104 | 1105 | //MARK:用于开始限制功能部分 1106 | 1107 | //获取限制状态 1108 | internal func limitedEnable() -> Bool { 1109 | 1110 | //如果未开启 1111 | if(!enableLimited!) 1112 | { 1113 | let unitSubArray:[UInt] = (pickerModeDict[pickerMode!]?.first!)! 1114 | if unitSubArray.first != UnitYear.rawValue && unitSubArray.last == UnitDay.rawValue{ 1115 | return true 1116 | } 1117 | } 1118 | //默认 1119 | return enableLimited! 1120 | 1121 | } 1122 | 1123 | //限制情况下的 数据源 1124 | internal func numberOfRowsInComponetForLimited(component:Int,unit:UInt) -> Int { 1125 | //当前情况下表示第一个 1126 | let minD:Date? = minDate 1127 | //当前情况下表示第一个 1128 | let maxD:Date? = maxDate 1129 | 1130 | var numberOfRows = 0 1131 | 1132 | //分类型处理 1133 | switch unit { 1134 | case UnitYear.rawValue: 1135 | if minD != nil && maxD != nil {//都有值 1136 | numberOfRows = calendar.components(UnitYear, from: getDateRemoveStopLastUnit(date: minD!, lastUnit:UnitYear ,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit:UnitYear,isFromDate: false), options: NSCalendar.Options.matchLast).year!+1 1137 | }else{ 1138 | numberOfRows = MaxRangeValue 1139 | } 1140 | break 1141 | case UnitMonth.rawValue: 1142 | if component == 0 { 1143 | if minD != nil && maxD != nil {//都有值 1144 | numberOfRows = calendar.components(UnitMonth, from: getDateRemoveStopLastUnit(date: minD!, lastUnit:UnitYear,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit:UnitYear,isFromDate: false), options: NSCalendar.Options.matchLast).month! 1145 | }else{ 1146 | numberOfRows = MaxRangeValue 1147 | } 1148 | }else 1149 | { 1150 | numberOfRows = 12 1151 | } 1152 | break 1153 | case UnitDay.rawValue: 1154 | if component == 0 { 1155 | if minD != nil && maxD != nil {//都有值 1156 | numberOfRows = calendar.components(UnitDay, from: getDateRemoveStopLastUnit(date: minD!, lastUnit:UnitDay,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit:UnitDay,isFromDate: false), options: NSCalendar.Options.matchLast).day!+1 1157 | }else if minD == nil && maxD == nil { 1158 | let comps:DateComponents = calendar.components(ComUnit, from: minD!) 1159 | if isLeapYear(year: (comps.year!)) { 1160 | numberOfRows = 366-1 1161 | }else 1162 | { 1163 | numberOfRows = 365-1 1164 | } 1165 | }else if minD != nil{//只有最小日期 1166 | let comps:DateComponents = calendar.components(ComUnit, from: minD!) 1167 | if isLeapYear(year: (comps.year!)) { 1168 | numberOfRows = 366-1 1169 | }else 1170 | { 1171 | numberOfRows = 365-1 1172 | } 1173 | }else if maxD != nil{ 1174 | let comps:DateComponents = calendar.components(ComUnit, from: maxD!) 1175 | if isLeapYear(year: (comps.year!)) { 1176 | numberOfRows = 366 1177 | }else 1178 | { 1179 | numberOfRows = 365 1180 | } 1181 | } 1182 | }else 1183 | { 1184 | numberOfRows = numberOfDaysInMonth(year:tempDateCompnents.year!, month: tempDateCompnents.month!) 1185 | } 1186 | break 1187 | case UnitHour.rawValue: 1188 | numberOfRows = 24 1189 | break 1190 | case UnitMinute.rawValue: 1191 | numberOfRows = 60 1192 | break 1193 | case UnitSecond.rawValue: 1194 | numberOfRows = 60 1195 | break 1196 | default: 1197 | 1198 | break 1199 | } 1200 | return numberOfRows 1201 | } 1202 | 1203 | //选中row 1204 | internal func selectedRowInComponentForLimited(component:Int,unit:UInt) -> Int { 1205 | 1206 | //当前情况下表示第一个 1207 | let minD:Date? = minDate 1208 | //当前情况下表示第一个 1209 | let maxD:Date? = maxDate 1210 | 1211 | var selectedRows:Int = 0 1212 | 1213 | //分类型处理 1214 | switch unit { 1215 | case UnitYear.rawValue: 1216 | if minD != nil{//都有值 1217 | selectedRows = calendar.components(UnitYear, from: getDateRemoveStopLastUnit(date: minD!, lastUnit: UnitYear,isFromDate: true), to: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitYear,isFromDate: false), options: NSCalendar.Options.matchLast).year! 1218 | }else if maxD != nil { 1219 | selectedRows = MaxRangeValue - calendar.components(UnitYear, from: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitYear,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit: UnitYear,isFromDate: false), options: NSCalendar.Options.matchLast).year! 1220 | }else if minD != nil && maxD != nil{ 1221 | selectedRows = calendar.components(UnitYear, from: getDateRemoveStopLastUnit(date: minD!, lastUnit: UnitYear,isFromDate: true), to: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitYear,isFromDate: false), options: NSCalendar.Options.matchLast).year! 1222 | } 1223 | break 1224 | case UnitMonth.rawValue: 1225 | if component == 0 { 1226 | if minD != nil && maxD != nil {//都有值 1227 | selectedRows = calendar.components(UnitMonth, from: getDateRemoveStopLastUnit(date: minD!, lastUnit: UnitMonth,isFromDate: true), to:getDateRemoveStopLastUnit(date: maxD!, lastUnit: UnitMonth,isFromDate: false), options: NSCalendar.Options.matchLast).month! 1228 | }else if minD == nil && maxD == nil { 1229 | selectedRows = currentIndex! 1230 | }else if minD != nil{ 1231 | selectedRows = calendar.components(UnitMonth, from: getDateRemoveStopLastUnit(date: minD!, lastUnit: UnitMonth,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit: UnitMonth,isFromDate: false), options: NSCalendar.Options.matchLast).month! 1232 | }else if maxD != nil{ 1233 | selectedRows = MaxRangeValue - calendar.components(UnitMonth, from: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitMonth,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit: UnitMonth,isFromDate: false), options: NSCalendar.Options.matchLast).month! 1234 | } 1235 | }else 1236 | { 1237 | if minD != nil && maxD != nil{ 1238 | selectedRows = (currentDateCompnents?.month)! - 1 1239 | }else{ 1240 | selectedRows = currentIndex! 1241 | } 1242 | } 1243 | break 1244 | case UnitDay.rawValue: 1245 | if component == 0 { 1246 | if minD != nil && maxD != nil {//都有值 1247 | selectedRows = calendar.components(UnitDay, from: getDateRemoveStopLastUnit(date: minD!, lastUnit: UnitDay,isFromDate: true), to: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitDay,isFromDate: false), options: NSCalendar.Options.matchLast).day! 1248 | }else if minD == nil && maxD == nil { 1249 | let comps:DateComponents = calendar.components(ComUnit, from: minD!) 1250 | 1251 | if isLeapYear(year: (comps.year!)) { 1252 | selectedRows = (366-1)/2 1253 | }else 1254 | { 1255 | selectedRows = (365-1)/2 1256 | } 1257 | }else if minD != nil{ 1258 | selectedRows = calendar.components(UnitDay, from: getDateRemoveStopLastUnit(date: minD!, lastUnit: UnitDay,isFromDate: true), to: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitDay,isFromDate: false), options: NSCalendar.Options.matchLast).day! 1259 | 1260 | }else if maxD != nil{ 1261 | let comps:DateComponents = calendar.components(ComUnit, from: maxD!) 1262 | if isLeapYear(year: (comps.year!)) { 1263 | 1264 | selectedRows = 366 - 1 - calendar.components(UnitDay, from: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitDay,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit: UnitDay,isFromDate: false), options:Option).day! 1265 | }else 1266 | { 1267 | selectedRows = 365 - 1 - calendar.components(UnitDay, from: getDateRemoveStopLastUnit(date: date!, lastUnit: UnitDay,isFromDate: true), to: getDateRemoveStopLastUnit(date: maxD!, lastUnit: UnitDay,isFromDate: false), options:Option).day! 1268 | } 1269 | } 1270 | }else 1271 | { 1272 | selectedRows = (currentDateCompnents?.day!)!-1//索引 1273 | } 1274 | break 1275 | case UnitHour.rawValue: 1276 | selectedRows = (currentDateCompnents?.hour!)! 1277 | break 1278 | case UnitMinute.rawValue: 1279 | selectedRows = (currentDateCompnents?.minute!)! 1280 | break 1281 | case UnitSecond.rawValue: 1282 | selectedRows = (currentDateCompnents?.second!)! 1283 | break 1284 | default: 1285 | 1286 | break 1287 | } 1288 | return selectedRows 1289 | } 1290 | 1291 | 1292 | //获取一个日期 对应的 前后一年内人的日期 1293 | private func getDateAddOrReduceYear(date:Date,isAdd:Bool) -> Date { 1294 | //判断最小日期是否在一年的范围内 1295 | var addComps:DateComponents = DateComponents() 1296 | if isAdd{ 1297 | addComps.year = 1 1298 | addComps.day = -1 1299 | }else{ 1300 | addComps.year = -1 1301 | addComps.day = 1 1302 | } 1303 | //日期 1304 | let lastDate:Date = calendar.date(byAdding: addComps, to:date, options: NSCalendar.Options.matchLast)! 1305 | 1306 | return lastDate 1307 | } 1308 | 1309 | 1310 | //去掉多余的日期部分,保证计算日期的差的准确度 1311 | func getDateRemoveStopLastUnit(date:Date,lastUnit:NSCalendar.Unit,isFromDate:Bool) -> Date { 1312 | //初始化 1313 | let unitArray:[UInt] = [UnitYear.rawValue,UnitMonth.rawValue,UnitDay.rawValue,UnitHour.rawValue,UnitMinute.rawValue,UnitSecond.rawValue] 1314 | 1315 | let dateComps:DateComponents = self.calendar.components(ComUnit, from: date) 1316 | 1317 | 1318 | var flag:Bool = true 1319 | var addDateComps:DateComponents = DateComponents() 1320 | 1321 | //遍历 1322 | for unitRawValue in unitArray{ 1323 | switch unitRawValue { 1324 | case UnitYear.rawValue: 1325 | if flag { 1326 | addDateComps.year = 0 1327 | }else{ 1328 | addDateComps.year = -(dateComps.year)! 1329 | } 1330 | //判断 1331 | if unitRawValue == lastUnit.rawValue{ 1332 | flag = false 1333 | } 1334 | break 1335 | case UnitMonth.rawValue: 1336 | if flag { 1337 | addDateComps.month = 0 1338 | }else{ 1339 | addDateComps.month = -(dateComps.month)! 1340 | } 1341 | //判断 1342 | if unitRawValue == lastUnit.rawValue{ 1343 | flag = false 1344 | } 1345 | break 1346 | case UnitDay.rawValue: 1347 | if flag { 1348 | addDateComps.day = 0 1349 | }else{ 1350 | addDateComps.day = -(dateComps.day)! 1351 | } 1352 | //判断 1353 | if unitRawValue == lastUnit.rawValue{ 1354 | flag = false 1355 | } 1356 | break 1357 | case UnitHour.rawValue: 1358 | if flag { 1359 | addDateComps.hour = 0 1360 | }else{ 1361 | addDateComps.hour = -(dateComps.hour)! 1362 | } 1363 | //判断 1364 | if unitRawValue == lastUnit.rawValue{ 1365 | flag = false 1366 | } 1367 | break 1368 | case UnitMinute.rawValue: 1369 | if flag { 1370 | addDateComps.minute = 0 1371 | }else{ 1372 | addDateComps.minute = -(dateComps.minute)! 1373 | } 1374 | //判断 1375 | if unitRawValue == lastUnit.rawValue{ 1376 | flag = false 1377 | } 1378 | break 1379 | case UnitSecond.rawValue: 1380 | if flag { 1381 | addDateComps.second = 0 1382 | }else{ 1383 | addDateComps.second = -(dateComps.second)! 1384 | } 1385 | //判断 1386 | if unitRawValue == lastUnit.rawValue{ 1387 | flag = false 1388 | } 1389 | break 1390 | default: 1391 | break 1392 | } 1393 | } 1394 | 1395 | if !isFromDate{ 1396 | addDateComps.second = 1 1397 | } 1398 | 1399 | let lastDate:Date = self.calendar.date(byAdding: addDateComps, to: date, options: NSCalendar.Options.matchLast)! 1400 | 1401 | return lastDate 1402 | } 1403 | } 1404 | --------------------------------------------------------------------------------