├── .gitignore ├── LICENSE ├── QBMDateTimePicker.podspec ├── README.md ├── Source ├── QBMComponent │ ├── QBMDatePickerModule.h │ └── QBMDatePickerModule.m ├── QBMCustomUI │ ├── QBMDatePickerView.h │ └── QBMDatePickerView.m ├── QBMDefine │ └── QBMDefine.h └── QBMTool │ ├── QBMUtil.h │ └── QBMUtil.m └── demo └── dateTimePicker.vue /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.DS_Store 11 | *.pbxuser # 忽略所有 .pbxuser 结尾的文件 12 | !default.pbxuser # 但 default.pbxuser除外 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 yolanderJing 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /QBMDateTimePicker.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint QBMDatePickerPlugin.podspec' to ensure this is a 3 | 4 | Pod::Spec.new do |s| 5 | 6 | 7 | 8 | s.name = "QBMDateTimePicker" 9 | s.version = "1.0.2" 10 | s.summary = "QBMDateTimePicker File" 11 | 12 | s.description = <<-DESC 13 | Testing private podspec,to verify availability 14 | DESC 15 | 16 | s.homepage = 'https://github.com/qbmFE/eros-plugin-IOS-dateTimePicker' 17 | 18 | s.license = "MIT" 19 | 20 | s.author = { "yolanderJing" => "zhangj@qbm360.com" } 21 | 22 | s.platform = :ios 23 | 24 | s.ios.deployment_target = "8.0" 25 | 26 | s.source = { :git => 'https://github.com/qbmFE/eros-plugin-IOS-dateTimePicker.git', :tag => s.version } 27 | 28 | #s.source_files = "Source/*" 29 | 30 | s.requires_arc = true 31 | 32 | s.subspec 'QBMComponent' do |ss| 33 | ss.source_files = "Source/QBMComponent/*.{h,m,mm}" 34 | ss.public_header_files = "QBMComponent/*.h" 35 | ss.requires_arc = true 36 | end 37 | 38 | s.subspec 'QBMCustomUI' do |ss| 39 | ss.source_files = "Source/QBMCustomUI/*.{h,m,mm}" 40 | ss.public_header_files = "QBMCustomUI/*.h" 41 | ss.requires_arc = true 42 | end 43 | 44 | s.subspec 'QBMTool' do |ss| 45 | ss.source_files = "Source/QBMTool/*.{h,m,mm}" 46 | ss.public_header_files = "QBMTool/*.h" 47 | ss.requires_arc = true 48 | end 49 | 50 | s.subspec 'QBMDefine' do |ss| 51 | ss.source_files = "Source/QBMDefine/*.{h,m,mm}" 52 | ss.public_header_files = "QBMDefine/*.h" 53 | ss.requires_arc = true 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 日期时间选择器插件 2 | 3 | 基于WEEX二次开发的日期时间选择器插件 4 | 5 | 安装 6 | ==================================== 7 | 8 | 1. 打开iOS目录`工程目录/platforms/ios/WeexEros`,编辑Podfile文件,增加以下代码; 9 | 10 | ``` 11 | pod 'QBMDateTimePicker', :git => 'https://github.com/qbmFE/eros-plugin-IOS-dateTimePicker.git', :tag => '1.0.2' 12 | ``` 13 | 14 | 2. 到此目录下执行 `pod update` 15 | 16 | 17 | 18 | 使用 19 | ==================================== 20 | 21 | 22 | ```js 23 | //引入module 24 | const dateTimePicker = weex.requireModule('dateTimePicker'); 25 | ``` 26 | 27 | 28 | 说明 29 | ==================================== 30 | 31 | 1. 使用本插件建议使用`pod 1.4.0`版本 32 | 2. 如果使用了`pod 1.5.0+`的版本,会提示这行代码问题: 33 | ``` 34 | #import 35 | ``` 36 | 把错误的地方上修改成如下代码就可以了。 37 | 38 | ``` 39 | #import 40 | ``` 41 | 42 | 43 | API 44 | ==================================== 45 | 46 | ```js 47 | // 示例 具体用法参考demo/dateTimePicker.vue 48 | dateTimePicker.open({ 49 | value: '',//必选,选中的值,格式为yyyy-MM-dd HH:mm;当value为空,默认选中当前时间;当value不为空时,选中value的返回值 50 | max: '',//可选,日期最大值,默认2099-12-31 23:59 51 | min: '',//可选,日期最小值,默认1900-12-31 00:00 52 | title: '',//可选,标题的文案,默认为空 53 | titleColor: '',//可选,默认为空,title不为空时有效,颜色值(#313131) 54 | confirmTitle: '', //确认按钮的文案,默认值(完成) 55 | confirmTitleColor: '', //确认按钮的文字颜色,默认值(#00b4ff) 56 | cancelTitle: '', //取消按钮的文案,默认值(取消) 57 | cancelTitleColor: '', //取消按钮的文字颜色,默认值(#313131) 58 | },(res) =>{//回调 59 | //返回字段 60 | //result{string}:success,cancel 61 | //data {string}:格式为yyyy-MM-dd HH:mm 62 | if(res.result === "success"){ 63 | //业务逻辑 64 | }else{ 65 | //业务逻辑 66 | } 67 | }); 68 | 69 | ``` 70 | 界面截图 71 | ==================================== 72 | 73 | ![](https://image.qbm360.com/demo/IOS-dateTimePicker.gif) 74 | 75 | 更新日志 76 | ==================================== 77 | 78 | * 发布iOS版日期时间选择器1.0.0 beta1(2018-05-31); 79 | * 调整插件UI,适配iPhone X,版本更新至1.0.2(2018-06-22); 80 | 81 | License 82 | ==================================== 83 | Copyright (c) 2018 钱保姆大前端 84 | 85 | -------------------------------------------------------------------------------- /Source/QBMComponent/QBMDatePickerModule.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBMDatePickerModule.h 3 | // WeexEros 4 | // 5 | // Created by qbm_ios on 2018/5/24. 6 | // Copyright © 2018年 qbm Company. All rights reserved. 7 | 8 | #import 9 | #import "WXModuleProtocol.h" 10 | @interface QBMDatePickerModule : NSObject 11 | 12 | @end 13 | 14 | -------------------------------------------------------------------------------- /Source/QBMComponent/QBMDatePickerModule.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBMDatePickerModule.m 3 | // WeexEros 4 | // 5 | // Created by qbm_ios on 2018/5/24. 6 | // Copyright © 2018年 qbm Company. All rights reserved. 7 | 8 | #import "QBMDatePickerModule.h" 9 | #import 10 | #import "QBMDefine.h" 11 | #import "WXComponentManager.h" 12 | #import "QBMDatePickerView.h" 13 | #import "WXConvert.h" 14 | #import 15 | 16 | @interface QBMDatePickerModule() 17 | 18 | @property(nonatomic,copy)NSString *title; 19 | @property(nonatomic,strong)UIColor *titleColor; 20 | @property(nonatomic,copy)NSString *cancelTitle; 21 | @property(nonatomic,copy)NSString *confirmTitle; 22 | @property(nonatomic,strong)UIColor *cancelTitleColor; 23 | @property(nonatomic,strong)UIColor *confirmTitleColor; 24 | 25 | @property(nonatomic,strong)QBMDatePickerView *pickerView; 26 | @property (nonatomic, strong) NSDate *selectedDate; 27 | @property(nonatomic,copy)WXModuleKeepAliveCallback callback; 28 | @end 29 | 30 | WX_PlUGIN_EXPORT_MODULE(dateTimePicker, QBMDatePickerModule) 31 | @implementation QBMDatePickerModule 32 | @synthesize weexInstance; 33 | 34 | WX_EXPORT_METHOD(@selector(open:callback:)) 35 | 36 | -(void)open:(NSDictionary *)options callback:(WXModuleKeepAliveCallback)callback 37 | { 38 | if (options[@"title"]) { 39 | self.title = [WXConvert NSString:options[@"title"]]; 40 | } 41 | if (options[@"titleColor"]) { 42 | self.titleColor = [WXConvert UIColor:options[@"titleColor"]]; 43 | } 44 | if (options[@"cancelTitle"]) { 45 | self.cancelTitle = [WXConvert NSString:options[@"cancelTitle"]]; 46 | } 47 | if (options[@"confirmTitle"]) { 48 | self.confirmTitle = [WXConvert NSString:options[@"confirmTitle"]]; 49 | } 50 | if (options[@"cancelTitleColor"]) { 51 | self.cancelTitleColor = [WXConvert UIColor:options[@"cancelTitleColor"]]; 52 | } 53 | if (options[@"confirmTitleColor"]) { 54 | self.confirmTitleColor = [WXConvert UIColor:options[@"confirmTitleColor"]]; 55 | } 56 | 57 | [self createBouncedView:options callback:(WXModuleKeepAliveCallback)callback]; 58 | 59 | } 60 | -(void)createBouncedView:(NSDictionary *)options callback:(WXModuleKeepAliveCallback)callback 61 | { 62 | self.callback = callback; 63 | UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 64 | [self.pickerView removeFromSuperview]; 65 | self.pickerView = [[QBMDatePickerView alloc]initWithFrame:CGRectMake(0, 0, Screen_width,Screen_height) withDic:options]; 66 | self.pickerView.delegate = self; 67 | [window addSubview:self.pickerView]; 68 | if (options[@"value"] && ![options[@"value"] isEqualToString:@""]) { 69 | 70 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 71 | [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm"]; 72 | NSDate *date = [dateFormatter dateFromString:options[@"value"]]; 73 | [self.pickerView showViewWithDate:date animation:YES]; 74 | } 75 | else{ 76 | [self.pickerView showViewWithDate:nil animation:YES]; 77 | } 78 | 79 | } 80 | 81 | #pragma mark - QBMDatePickerViewDelegate 82 | - (void)datePickerView:(QBMDatePickerView *)datePickerView didSelectDate:(NSDate *)date { 83 | self.selectedDate = date; 84 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 85 | [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm"]; 86 | NSString *value = [dateFormatter stringFromDate:self.selectedDate]; 87 | if (self.callback) { 88 | self.callback(@{ @"result": @"success",@"data":value},NO); 89 | self.callback=nil; 90 | } 91 | } 92 | -(void)cancleEvent{ 93 | if (self.callback) { 94 | self.callback(@{ @"result": @"cancel"},NO); 95 | self.callback = nil; 96 | } 97 | } 98 | @end 99 | 100 | -------------------------------------------------------------------------------- /Source/QBMCustomUI/QBMDatePickerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBMDatePickerView.h 3 | // WeexEros 4 | // 5 | // Created by qbm_ios on 2018/5/24. 6 | // Copyright © 2018年 qbm Company. All rights reserved. 7 | 8 | #import 9 | 10 | /** 11 | * 日期选择器显示模式。 12 | */ 13 | typedef NS_ENUM(NSInteger, QBMDatePickerViewShowModel) { 14 | QBMDatePickerViewShowModelDefalut, //显示年,月,日,时,分。 15 | QBMDatePickerViewShowModelYearMonthDayHour, //显示年,月,日,时。 16 | QBMDatePickerViewShowModelYearMonthDay, //显示年,月,日。 17 | }; 18 | 19 | /** 20 | * 日期选择器时间范围。 21 | */ 22 | typedef NS_ENUM(NSInteger, QBMDatePickerViewDateRangeModel) { 23 | QBMDatePickerViewDateRangeModelCurrent, //最大时间为当前系统时间。用途:例如选择生日的时候不可能大于当前时间。 24 | QBMDatePickerViewDateRangeModelCustom //自定义时间范围。可通过下面的属性minYear和maxYear设定。 25 | }; 26 | 27 | @protocol QBMDatePickerViewDelegate; 28 | 29 | @interface QBMDatePickerView : UIView 30 | 31 | @property (nonatomic, assign) NSInteger minYear; //时间列表最小年份,不能大于最大年份。默认为1970年。 32 | @property (nonatomic, assign) NSInteger maxYear; //时间列表最大年份,不能小于最小年份。默认为当前年份。注意:仅当属性datePickerViewDateRangeModel的值为QBMDatePickerViewDateRangeModelCustom时才有效。 33 | 34 | @property (nonatomic, assign, readonly, getter=isVisible) BOOL visible; //YES:处于显示状态,NO:处于隐藏状态。 35 | 36 | @property (nonatomic, assign) QBMDatePickerViewShowModel datePickerViewShowModel; //日期显示模式,默认为QBMDatePickerViewShowModelDefalut。 37 | 38 | @property (nonatomic, assign) QBMDatePickerViewDateRangeModel datePickerViewDateRangeModel; //时间范围模式,默认为QBMDatePickerViewDateRangeModelCurrent。 39 | 40 | @property (nonatomic, assign) id delegate; 41 | 42 | /** 43 | * 显示时间选择器。 44 | * 45 | * @param date 初始显示日期,传nil则默认显示当前日期。 46 | * @param animation YES:有动画,NO:无动画。 47 | */ 48 | - (void)showViewWithDate:(NSDate *)date animation:(BOOL)animation; 49 | 50 | /** 51 | * 隐藏时间选择器。 52 | * 53 | * @param animation YES:有动画,NO:无动画。 54 | */ 55 | - (void)hideViewWithAnimation:(BOOL)animation; 56 | - (id)initWithFrame:(CGRect)frame withDic:(NSDictionary *)dict; 57 | @end 58 | 59 | @protocol QBMDatePickerViewDelegate 60 | 61 | - (void)datePickerView:(QBMDatePickerView *)datePickerView didSelectDate:(NSDate *)date; 62 | -(void)cancleEvent; 63 | @end 64 | 65 | -------------------------------------------------------------------------------- /Source/QBMCustomUI/QBMDatePickerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBMDatePickerView.m 3 | // WeexEros 4 | // 5 | // Created by qbm_ios on 2018/5/24. 6 | // Copyright © 2018年 qbm Company. All rights reserved. 7 | 8 | 9 | #import "QBMDatePickerView.h" 10 | #import "QBMDefine.h" 11 | #import "QBMUtil.h" 12 | 13 | #define QBMTOOLBAR_HEIGHT 45.0*BILI //顶部工具栏高度。 14 | #define QBMROW_HEIGHT 44.0*BILI 15 | #define QBMDURATION 0.3 //动画时长。 16 | #define QBMTITLE_LABEL_START_TAG 1 //从左往右第一个标题Label的Tag值。 17 | 18 | @interface QBMDatePickerView () { 19 | UIPickerView *datePickerView; 20 | 21 | 22 | //数据源。 23 | NSMutableArray *yearArray; 24 | NSMutableArray *monthArray; 25 | NSMutableArray *dayArray; 26 | NSMutableArray *hourArray; 27 | NSMutableArray *minuteArray; 28 | 29 | //最大值。 30 | NSInteger maxMonth; 31 | NSInteger maxDay; 32 | NSInteger maxHour; 33 | NSInteger maxMinute; 34 | 35 | //最小值 36 | NSInteger minMonth; 37 | NSInteger minDay; 38 | NSInteger minHour; 39 | NSInteger minMinute; 40 | 41 | NSMutableArray *minYearArray; 42 | NSMutableArray *minMonthArray; 43 | NSMutableArray *minDayArray; 44 | NSMutableArray *minHourArray; 45 | NSMutableArray *minMinuteArray; 46 | 47 | //选中行数。 48 | NSInteger selectedYearRow; 49 | NSInteger selectedMonthRow; 50 | NSInteger selectedDayRow; 51 | NSInteger selectedHourRow; 52 | NSInteger selectedMinuteRow; 53 | 54 | UILabel *titleLabel; 55 | CGSize sizeOfYear; 56 | CGSize sizeOfOther; 57 | CGSize sizeOfTitle; 58 | } 59 | @property(nonatomic,strong)UIView *contentView; 60 | @end 61 | @implementation QBMDatePickerView 62 | 63 | - (id)initWithFrame:(CGRect)frame withDic:(NSDictionary *)dict{ 64 | if (self = [super initWithFrame:frame]) { 65 | NSDictionary *dict16 = [[NSDictionary alloc] initWithObjectsAndKeys:[UIFont systemFontOfSize:16*BILIWIDTH],NSFontAttributeName, nil]; 66 | sizeOfYear= [@"2008" sizeWithAttributes:dict16]; 67 | sizeOfOther= [@"20" sizeWithAttributes:dict16]; 68 | 69 | NSDictionary *dict12 = [[NSDictionary alloc] initWithObjectsAndKeys:[UIFont systemFontOfSize:12*BILIWIDTH],NSFontAttributeName, nil]; 70 | sizeOfTitle=[@"年" sizeWithAttributes:dict12]; 71 | UIControl *backGroundView=[[UIControl alloc]initWithFrame:self.bounds]; 72 | backGroundView.backgroundColor=[UIColor blackColor]; 73 | [backGroundView addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; 74 | backGroundView.alpha=0.65; 75 | [self addSubview:backGroundView]; 76 | 77 | self.contentView=[[UIView alloc]init]; 78 | if (kDevice_Is_iPhoneX) 79 | { 80 | self.contentView.frame=CGRectMake(0, backGroundView.frame.size.height-265*BILI-34, Screen_width, 265*BILI+34); 81 | } 82 | else{ 83 | self.contentView.frame=CGRectMake(0, backGroundView.frame.size.height-265*BILI, Screen_width, 265*BILI); 84 | } 85 | 86 | self.contentView.backgroundColor = [UIColor whiteColor]; 87 | [self addSubview:self.contentView]; 88 | 89 | _visible = NO; 90 | _datePickerViewShowModel = QBMDatePickerViewShowModelDefalut; 91 | _datePickerViewDateRangeModel = QBMDatePickerViewDateRangeModelCustom; 92 | [self __initView:(NSDictionary *)dict]; 93 | [self __initData:(NSDictionary *)dict]; 94 | } 95 | return self; 96 | } 97 | 98 | - (void)layoutSubviews { 99 | CGFloat width = self.contentView.frame.size.width; 100 | CGFloat height = self.contentView.frame.size.height; 101 | if (kDevice_Is_iPhoneX) 102 | { 103 | datePickerView.frame = CGRectMake(0, QBMTOOLBAR_HEIGHT,width, height - QBMTOOLBAR_HEIGHT-34); 104 | } 105 | else{ 106 | datePickerView.frame = CGRectMake(0, QBMTOOLBAR_HEIGHT,width, height - QBMTOOLBAR_HEIGHT); 107 | } 108 | 109 | } 110 | 111 | - (void)__initView:(NSDictionary *)dict { 112 | 113 | 114 | //顶部工具栏。 115 | titleLabel = [[UILabel alloc] initWithFrame:CGRectMake((Screen_width-200)/2, 0, 200, QBMTOOLBAR_HEIGHT)]; 116 | [titleLabel setBackgroundColor:[UIColor clearColor]]; 117 | if (dict[@"title"]) { 118 | titleLabel.text=[NSString stringWithFormat:@"%@",dict[@"title"]]; 119 | } 120 | else{ 121 | titleLabel.text=@""; 122 | } 123 | if (dict[@"titleColor"]) { 124 | [titleLabel setTextColor:[QBMUtil colorWithHexString:dict[@"titleColor"]]]; 125 | } 126 | else{ 127 | [titleLabel setTextColor:[QBMUtil colorWithHexString:@"#313131"]]; 128 | } 129 | [titleLabel setFont:[UIFont systemFontOfSize:15.0*BILIWIDTH]]; 130 | [titleLabel setTextAlignment:NSTextAlignmentCenter]; 131 | [self.contentView addSubview:titleLabel]; 132 | 133 | 134 | UIButton * cancel = [UIButton buttonWithType:UIButtonTypeCustom]; 135 | cancel.frame=CGRectMake(0, 0,(Screen_width-200)/2 , QBMTOOLBAR_HEIGHT); 136 | if (dict[@"cancelTitle"] && ![dict[@"cancelTitle"] isEqualToString:@""]) { 137 | [cancel setTitle:[NSString stringWithFormat:@"%@",dict[@"cancelTitle"]] forState:UIControlStateNormal]; 138 | } 139 | else{ 140 | [cancel setTitle:@"取消" forState:UIControlStateNormal]; 141 | } 142 | if (dict[@"cancelTitleColor"] && ![dict[@"cancelTitleColor"] isEqualToString:@""]) { 143 | [cancel setTitleColor:[QBMUtil colorWithHexString:dict[@"cancelTitleColor"]] forState:UIControlStateNormal]; 144 | } 145 | else{ 146 | [cancel setTitleColor:[QBMUtil colorWithHexString:@"#313131"] forState:UIControlStateNormal]; 147 | } 148 | cancel.titleLabel.font = [UIFont systemFontOfSize:15*BILIWIDTH]; 149 | [cancel addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; 150 | cancel.tag = 100; 151 | [self.contentView addSubview:cancel]; 152 | 153 | UIButton * confirm = [UIButton buttonWithType:UIButtonTypeCustom]; 154 | confirm.frame=CGRectMake(Screen_width-(Screen_width-200)/2, 0,(Screen_width-200)/2, QBMTOOLBAR_HEIGHT); 155 | 156 | if (dict[@"confirmTitle"] && ![dict[@"confirmTitle"] isEqualToString:@""]) { 157 | [confirm setTitle:[NSString stringWithFormat:@"%@",dict[@"confirmTitle"]] forState:UIControlStateNormal]; 158 | } 159 | else{ 160 | [confirm setTitle:@"完成" forState:UIControlStateNormal]; 161 | } 162 | if (dict[@"confirmTitleColor"] && ![dict[@"confirmTitleColor"] isEqualToString:@""]) { 163 | [confirm setTitleColor:[QBMUtil colorWithHexString:dict[@"confirmTitleColor"]] forState:UIControlStateNormal]; 164 | } 165 | else{ 166 | [confirm setTitleColor:[QBMUtil colorWithHexString:@"#00B4FF"] forState:UIControlStateNormal]; 167 | } 168 | 169 | confirm.titleLabel.font = [UIFont systemFontOfSize:15*BILIWIDTH]; 170 | [confirm addTarget:self action:@selector(completion) forControlEvents:UIControlEventTouchUpInside]; 171 | confirm.tag = 200; 172 | [self.contentView addSubview:confirm]; 173 | 174 | //分割线 175 | UIView *lineView=[[UIView alloc]initWithFrame:CGRectMake(0, QBMTOOLBAR_HEIGHT-0.5, self.frame.size.width, 0.5)]; 176 | lineView.backgroundColor=[QBMUtil colorWithHexString:@"#e5e5e5"]; 177 | [self.contentView addSubview:lineView]; 178 | 179 | //UIPickerView. 180 | datePickerView = [[UIPickerView alloc]init]; 181 | datePickerView.backgroundColor = [UIColor whiteColor]; 182 | datePickerView.showsSelectionIndicator = YES; 183 | datePickerView.delegate = self; 184 | datePickerView.dataSource = self; 185 | [self.contentView addSubview:datePickerView]; 186 | 187 | //年月日 188 | // CGFloat frameOri=0.0f; 189 | NSArray *titleArray=[NSArray arrayWithObjects:@"年", @"月",@"日",@":",nil]; 190 | for(int i=0;i<4;i++){ 191 | UILabel *lable=[[UILabel alloc]init]; 192 | lable.textAlignment=NSTextAlignmentCenter; 193 | lable.font=[UIFont systemFontOfSize:12*BILIWIDTH]; 194 | lable.textColor=[QBMUtil colorWithHexString:@"#666666"]; 195 | lable.text=[NSString stringWithFormat:@"%@",titleArray[i]]; 196 | [self.contentView addSubview:lable]; 197 | 198 | switch (i) { 199 | case 0: 200 | lable.frame=CGRectMake(70*BILIWIDTH, 133*BILI, sizeOfTitle.width, QBMROW_HEIGHT); 201 | break; 202 | case 1: 203 | lable.frame=CGRectMake(133*BILIWIDTH, 133*BILI, sizeOfTitle.width, QBMROW_HEIGHT); 204 | break; 205 | case 2: 206 | lable.frame=CGRectMake(190*BILIWIDTH, 133*BILI, sizeOfTitle.width, QBMROW_HEIGHT); 207 | break; 208 | case 3: 209 | lable.frame=CGRectMake(285*BILIWIDTH, 133*BILI, sizeOfTitle.width, QBMROW_HEIGHT); 210 | break; 211 | default: 212 | break; 213 | } 214 | } 215 | } 216 | - (void)__initData:(NSDictionary *)dict { 217 | //初始化最大值。 218 | NSDate *minDate; 219 | NSDateFormatter *formatter = [[NSDateFormatter alloc]init]; 220 | [formatter setDateFormat:@"yyyy-MM-dd HH:mm"]; 221 | if (dict[@"min"] && ![dict[@"min"] isEqualToString:@""]) { 222 | minDate = [formatter dateFromString:[NSString stringWithFormat:@"%@",dict[@"min"]]]; 223 | } 224 | else{ 225 | minDate = [formatter dateFromString:@"1900-12-31 00:00"]; 226 | } 227 | NSDate* maxDate; 228 | if (dict[@"max"] && ![dict[@"max"] isEqualToString:@""]) { 229 | maxDate = [formatter dateFromString:[NSString stringWithFormat:@"%@",dict[@"max"]]]; 230 | } 231 | else{ 232 | maxDate = [formatter dateFromString:@"2099-12-31 23:59"]; 233 | } 234 | NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 235 | NSCalendarUnit calendarUnit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute; 236 | 237 | NSDateComponents *minDateComponents = [calendar components:calendarUnit fromDate:minDate]; 238 | _minYear = [minDateComponents year]; 239 | minMonth = [minDateComponents month]; 240 | minDay= [minDateComponents day]; 241 | minHour = [minDateComponents hour]; 242 | minMinute = [minDateComponents minute]; 243 | //初始化最小时间。 244 | 245 | NSInteger oriMonth = minMonth; 246 | NSInteger oriDay = minDay; 247 | NSInteger oriHour = minHour; 248 | NSInteger oriMinute = minMinute; 249 | //初始化最小月 天 时分 250 | minMonthArray = [[NSMutableArray alloc]init]; 251 | for (NSInteger i = 0; i < (12-oriMonth+1); i++) { 252 | [minMonthArray addObject:[NSString stringWithFormat:@"%ld",oriMonth+i]]; 253 | } 254 | minDayArray = [[NSMutableArray alloc]init]; 255 | 256 | int days=31; 257 | if (oriMonth==2) { 258 | //2月份的处理 259 | if (((_minYear % 4 == 0 && _minYear % 100 != 0 ))|| (_minYear % 400 == 0)) { 260 | //最小年是闰年 261 | days = 29; 262 | } 263 | else 264 | { 265 | days = 28; 266 | } 267 | } 268 | for (NSInteger i = 0; i < (days-oriDay+1); i++) { 269 | [minDayArray addObject:[NSString stringWithFormat:@"%ld",oriDay+i]]; 270 | } 271 | 272 | minHourArray = [[NSMutableArray alloc]init]; 273 | for (NSInteger i = 0; i < (23-oriHour+1); i++) { 274 | [minHourArray addObject:[NSString stringWithFormat:@"%ld",oriHour+i]]; 275 | } 276 | minMinuteArray = [[NSMutableArray alloc]init]; 277 | for (NSInteger i = 0; i < (59-oriMinute+1); i++) { 278 | [minMinuteArray addObject:[NSString stringWithFormat:@"%ld",oriMinute+i]]; 279 | } 280 | 281 | NSDateComponents *currentDateComponents = [calendar components:calendarUnit fromDate:maxDate]; 282 | _maxYear = [currentDateComponents year]; 283 | maxMonth = [currentDateComponents month]; 284 | maxDay = [currentDateComponents day]; 285 | maxHour = [currentDateComponents hour]; 286 | maxMinute = [currentDateComponents minute]; 287 | //初始化最大时间。 288 | NSInteger lastYear = _maxYear; 289 | NSInteger lastMonth = maxMonth; 290 | NSInteger lastDay = maxDay; 291 | NSInteger lastHour = maxHour; 292 | NSInteger lastMinute = maxMinute; 293 | 294 | //初始化年份数组(范围自定义)。 295 | yearArray = [[NSMutableArray alloc]init]; 296 | for (NSInteger i = _minYear; i <= lastYear; i ++) { 297 | [yearArray addObject:[NSString stringWithFormat:@"%ld",i]]; 298 | } 299 | 300 | //初始化月份数组(1-12)。 301 | monthArray = [[NSMutableArray alloc]init]; 302 | for (NSInteger i = 1; i <= lastMonth; i++) { 303 | [monthArray addObject:[NSString stringWithFormat:@"%ld",i]]; 304 | } 305 | 306 | //初始化天数数组(1-31)。 307 | dayArray = [[NSMutableArray alloc]init]; 308 | for (NSInteger i = 1; i <= lastDay; i++) { 309 | [dayArray addObject:[NSString stringWithFormat:@"%ld",i]]; 310 | } 311 | 312 | //初始化小时数组(0-23)。 313 | hourArray = [[NSMutableArray alloc]init]; 314 | for (NSInteger i = 0; i <= lastHour; i++) { 315 | [hourArray addObject:[NSString stringWithFormat:@"%ld",i]]; 316 | } 317 | 318 | //初始化分钟数组(0-59)。 319 | minuteArray = [[NSMutableArray alloc]init]; 320 | for (NSInteger i = 0; i <= lastMinute; i++) { 321 | [minuteArray addObject:[NSString stringWithFormat:@"%ld",i]]; 322 | } 323 | 324 | } 325 | 326 | #pragma mark - Public 327 | - (void)showViewWithDate:(NSDate *)date animation:(BOOL)animation{ 328 | [self __showWithAnimation:animation]; 329 | 330 | if (!date) { 331 | date = [NSDate date]; 332 | } 333 | 334 | NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 335 | NSCalendarUnit calendarUnit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute; 336 | NSDateComponents *dateComponents = [calendar components:calendarUnit fromDate:date]; 337 | 338 | NSInteger year = [dateComponents year]; 339 | NSInteger month = [dateComponents month]; 340 | NSInteger day = [dateComponents day]; 341 | NSInteger hour = [dateComponents hour]; 342 | NSInteger minute = [dateComponents minute]; 343 | //加0处理 344 | NSString *monthStr; 345 | NSString *dayStr; 346 | NSString *hourStr; 347 | NSString *minuteStr; 348 | monthStr=month<10?[NSString stringWithFormat:@"0%ld",month]:[NSString stringWithFormat:@"%ld",month]; 349 | dayStr=day<10?[NSString stringWithFormat:@"0%ld",day]:[NSString stringWithFormat:@"%ld",day]; 350 | hourStr=hour<10?[NSString stringWithFormat:@"0%ld",hour]:[NSString stringWithFormat:@"%ld",hour]; 351 | minuteStr=minute<10?[NSString stringWithFormat:@"0%ld",minute]:[NSString stringWithFormat:@"%ld",minute]; 352 | 353 | if (_datePickerViewDateRangeModel == QBMDatePickerViewDateRangeModelCurrent) { 354 | //更新时间最大值为当前系统时间。 355 | NSDateComponents *currentDateComponents = [calendar components:calendarUnit fromDate:[NSDate date]]; 356 | _maxYear = [currentDateComponents year]; 357 | maxMonth = [currentDateComponents month]; 358 | maxDay = [currentDateComponents day]; 359 | maxHour = [currentDateComponents hour]; 360 | maxMinute = [currentDateComponents minute]; 361 | 362 | /** 363 | * 显示时间是否小于等于当前系统时间。 364 | * PS:这里比较时间之所以不用earlierDate:或laterDate:方法,是因为这里没有比较秒数。 365 | */ 366 | BOOL isEarly = NO; 367 | if (year == _maxYear && month == maxMonth && day == maxDay && hour == maxHour && minute && maxMinute) { 368 | //相等情况。 369 | isEarly = YES; 370 | }else { 371 | if (year < _maxYear) { 372 | isEarly = YES; 373 | }else if (month < maxMonth) { 374 | isEarly = YES; 375 | }else if (day < maxDay) { 376 | isEarly = YES; 377 | }else if (hour < maxHour) { 378 | isEarly = YES; 379 | }else if (minute < maxMinute) { 380 | isEarly = YES; 381 | } 382 | } 383 | NSAssert(isEarly, @"当前模式下不允许显示时间大于当前系统时间,如有需要请更换时间范围模式!"); 384 | 385 | }else if (_datePickerViewDateRangeModel == QBMDatePickerViewDateRangeModelCustom) { 386 | /** 387 | * 下面两个步骤,可以根据自己需要自选一个。 388 | * 步骤1:限定最大年份,如果超出大值则终止。 389 | * 步骤2:如果超出最大年份,则更新最大年份值继续显示。 390 | * 391 | * PS:这里选择步骤2. 392 | */ 393 | 394 | /* 395 | 396 | //步骤1. 397 | NSAssert(_maxYear > year, @"年份超出最大范围,如有需要请更新最大年份范围!"); 398 | 399 | */ 400 | 401 | //步骤2。 402 | if (year > _maxYear) { 403 | _maxYear = year; 404 | } 405 | } 406 | 407 | 408 | [self resetYearArray]; 409 | [self resetMonthArrayWithYear:year]; 410 | [self resetDayArrayWithYear:year month:month]; 411 | [self resetHourArrayWithYear:year month:month day:day]; 412 | [self resetMinuteArrayWithYear:year month:month day:day hour:hour]; 413 | [datePickerView reloadAllComponents]; 414 | 415 | if (_minYear>year || (_minYear==year && minMonth>month) || (_minYear==year && minMonth==month && minDay>day)) { 416 | // UIAlertView *alertView= [[UIAlertView alloc]initWithTitle:@"提示" message:@"数据异常!" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; 417 | // [alertView show]; 418 | // return; 419 | 420 | [datePickerView selectRow:0 inComponent:0 animated:YES]; 421 | [datePickerView selectRow:0 inComponent:1 animated:YES]; 422 | [datePickerView selectRow:0 inComponent:2 animated:YES]; 423 | 424 | if (_datePickerViewShowModel == QBMDatePickerViewShowModelDefalut) { 425 | [datePickerView selectRow:0 inComponent:3 animated:YES]; 426 | [datePickerView selectRow:0 inComponent:4 animated:YES]; 427 | }else if (_datePickerViewShowModel == QBMDatePickerViewShowModelYearMonthDayHour) { 428 | [datePickerView selectRow:0 inComponent:3 animated:YES]; 429 | } 430 | //赋值 431 | selectedYearRow=0; 432 | selectedMonthRow=0; 433 | selectedDayRow=0; 434 | selectedHourRow=0; 435 | selectedMinuteRow=0; 436 | } 437 | else{ 438 | [datePickerView selectRow:[yearArray indexOfObject:[NSString stringWithFormat:@"%ld",year]] inComponent:0 animated:YES]; 439 | [datePickerView selectRow:[monthArray indexOfObject:monthStr] inComponent:1 animated:YES]; 440 | [datePickerView selectRow:[dayArray indexOfObject:dayStr] inComponent:2 animated:YES]; 441 | 442 | if (_datePickerViewShowModel == QBMDatePickerViewShowModelDefalut) { 443 | if ([hourArray containsObject:hourStr]) { 444 | [datePickerView selectRow:[hourArray indexOfObject:hourStr] inComponent:3 animated:YES]; 445 | } 446 | if ([minuteArray containsObject:minuteStr]) { 447 | [datePickerView selectRow:[minuteArray indexOfObject:minuteStr] inComponent:4 animated:YES]; 448 | } 449 | 450 | }else if (_datePickerViewShowModel == QBMDatePickerViewShowModelYearMonthDayHour) { 451 | [datePickerView selectRow:[hourArray indexOfObject:hourStr] inComponent:3 animated:YES]; 452 | } 453 | //赋值 454 | selectedYearRow=[yearArray indexOfObject:[NSString stringWithFormat:@"%ld",year]]; 455 | selectedMonthRow=[monthArray indexOfObject:monthStr]; 456 | selectedDayRow=[dayArray indexOfObject:dayStr]; 457 | selectedHourRow=[hourArray indexOfObject:hourStr]; 458 | selectedMinuteRow=[minuteArray indexOfObject:minuteStr]; 459 | 460 | } 461 | 462 | } 463 | 464 | - (void)hideViewWithAnimation:(BOOL)animation { 465 | [self __hideWithAnimation:animation]; 466 | } 467 | 468 | #pragma mark - Private 469 | /** 470 | * 除了重置年份外,月、天、时和分均在原有基础上新增或减少,避免过多无谓的循环。 471 | */ 472 | 473 | #pragma mark 重置年份 474 | - (void)resetYearArray 475 | { 476 | //先判断是否需要重置。 477 | NSInteger minYear =_minYear; 478 | NSInteger maxYear = _maxYear; 479 | if (_minYear == minYear && _maxYear == maxYear) { 480 | return; 481 | } 482 | 483 | [yearArray removeAllObjects]; 484 | for (NSInteger i = _minYear; i <= _maxYear; i++) { 485 | [yearArray addObject:[NSString stringWithFormat:@"%ld",i]]; 486 | } 487 | 488 | //重置年份选中行,防止越界。 489 | selectedYearRow = selectedYearRow > [yearArray count] - 1 ? [yearArray count] - 1 : selectedYearRow; 490 | } 491 | 492 | #pragma mark 重置月份 493 | - (void)resetMonthArrayWithYear:(NSInteger)year 494 | { 495 | NSInteger totalMonth = 12; 496 | NSInteger origMonth = 1; 497 | [monthArray removeAllObjects]; 498 | if(_minYear == year){ 499 | origMonth = minMonth; //限制月份。 500 | NSInteger lastMonth=12; 501 | if(_maxYear == _minYear) { 502 | lastMonth=maxMonth; 503 | } 504 | for (NSInteger i=0; i<(lastMonth-origMonth+1);i++) { 505 | 506 | if (origMonth+i<10) { 507 | [monthArray addObject:[NSString stringWithFormat:@"0%d",origMonth+i]]; 508 | } 509 | else{ 510 | [monthArray addObject:[NSString stringWithFormat:@"%d",origMonth+i]]; 511 | } 512 | } 513 | } 514 | else if (_maxYear == year) { 515 | totalMonth = maxMonth; //限制月份。 516 | for (NSInteger i=1; i<=totalMonth;i++) { 517 | if (i<10) { 518 | [monthArray addObject:[NSString stringWithFormat:@"0%d",i]]; 519 | } 520 | else{ 521 | [monthArray addObject:[NSString stringWithFormat:@"%d",i]]; 522 | } 523 | } 524 | } 525 | else{ 526 | for ( int i=0; i< 12; i++) { 527 | if (i+1<10) { 528 | [monthArray addObject:[NSString stringWithFormat:@"0%d",i+1]]; 529 | } 530 | else{ 531 | [monthArray addObject:[NSString stringWithFormat:@"%d",i+1]]; 532 | } 533 | } 534 | } 535 | //重置月份选中行,防止越界。 536 | selectedMonthRow = selectedMonthRow > [monthArray count] - 1 ? [monthArray count] - 1: selectedMonthRow; 537 | } 538 | 539 | #pragma mark 重置天数 540 | - (void)resetDayArrayWithYear:(NSInteger)year month:(NSInteger)month { 541 | NSInteger oriDay=0; 542 | NSInteger totalDay = 0; 543 | [dayArray removeAllObjects]; 544 | if (_minYear == year && minMonth == month) { 545 | oriDay = minDay; 546 | totalDay=[self getDaysWithSelectYear:_minYear andMonth:minMonth]; 547 | if (_minYear ==_maxYear) { 548 | //最大年与最小年相同 且月份相同 549 | totalDay=maxDay; 550 | } 551 | for (NSInteger i=0; i<(totalDay-oriDay+1);i++) { 552 | 553 | if (oriDay+i<10) { 554 | [dayArray addObject:[NSString stringWithFormat:@"0%d",oriDay+i]]; 555 | } 556 | else{ 557 | [dayArray addObject:[NSString stringWithFormat:@"%d",oriDay+i]]; 558 | } 559 | } 560 | } 561 | else if (_maxYear == year) { 562 | 563 | if (_maxYear == year && maxMonth == month) { 564 | totalDay = maxDay; //限制最大天数。 565 | }else { 566 | totalDay=[self getDaysWithSelectYear:year andMonth:month]; 567 | } 568 | 569 | for (int i=0; i [dayArray count] - 1 ? [dayArray count] - 1 : selectedDayRow; 592 | } 593 | 594 | #pragma mark 重置小时 595 | - (void)resetHourArrayWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day { 596 | NSInteger totalHour = 23; 597 | NSInteger oriHour=0; 598 | [hourArray removeAllObjects]; 599 | 600 | if(_minYear == year && minMonth == month && minDay == day){ 601 | oriHour = minHour; 602 | //最大年与最小年相同 且月份相同 天数相同(2018.5.30 9:00-2018.5.30 19:00) 603 | if (_maxYear==_minYear) { 604 | totalHour=maxHour; 605 | } 606 | for (NSInteger i=0; i<(totalHour-oriHour+1);i++) { 607 | if (oriHour+i<10) { 608 | [hourArray addObject:[NSString stringWithFormat:@"0%ld",oriHour+i]]; 609 | } 610 | else{ 611 | [hourArray addObject:[NSString stringWithFormat:@"%ld",oriHour+i]]; 612 | } 613 | } 614 | } 615 | else if (_maxYear == year) { 616 | if (_maxYear == year && maxMonth == month && maxDay == day) { 617 | totalHour = maxHour; //限制小时。 618 | } 619 | for (int i=0; i<=totalHour; i++) { 620 | if (i<10) { 621 | [hourArray addObject:[NSString stringWithFormat:@"0%d",i]]; 622 | } 623 | else{ 624 | [hourArray addObject:[NSString stringWithFormat:@"%d",i]]; 625 | } 626 | } 627 | } 628 | else{ 629 | for (int i=0; i<=totalHour; i++) { 630 | 631 | if (i<10) { 632 | [hourArray addObject:[NSString stringWithFormat:@"0%d",i]]; 633 | } 634 | else{ 635 | [hourArray addObject:[NSString stringWithFormat:@"%d",i]]; 636 | } 637 | } 638 | } 639 | //重置小时选中行,防止越界。 640 | selectedHourRow = selectedHourRow > [hourArray count] - 1 ? [hourArray count] - 1 : selectedHourRow; 641 | } 642 | 643 | #pragma mark 重置分钟 644 | - (void)resetMinuteArrayWithYear:(NSInteger)year 645 | month:(NSInteger)month 646 | day:(NSInteger)day 647 | hour:(NSInteger)hour { 648 | NSInteger oriMinute=0; 649 | NSInteger totalMinute = 59; 650 | [minuteArray removeAllObjects]; 651 | if (_minYear == year && minMonth == month && minDay == day && minHour == hour){ 652 | oriMinute = minMinute; 653 | for (NSInteger i=0; i<(totalMinute-oriMinute+1);i++) { 654 | if (oriMinute+i<10) { 655 | [minuteArray addObject:[NSString stringWithFormat:@"0%ld",oriMinute+i]]; 656 | } 657 | else{ 658 | [minuteArray addObject:[NSString stringWithFormat:@"%ld",oriMinute+i]]; 659 | } 660 | 661 | } 662 | } 663 | else if (_maxYear == year) { 664 | if (_maxYear == year && maxMonth == month && maxDay == day && maxHour == hour) { 665 | totalMinute = maxMinute; //限制分钟。 666 | } 667 | for (int i=0; i<=totalMinute; i++) { 668 | if (i<10) { 669 | [minuteArray addObject:[NSString stringWithFormat:@"0%d",i]]; 670 | } 671 | else{ 672 | [minuteArray addObject:[NSString stringWithFormat:@"%d",i]]; 673 | } 674 | } 675 | } 676 | 677 | else{ 678 | for (int i=0; i<=totalMinute; i++) { 679 | 680 | if (i<10) { 681 | [minuteArray addObject:[NSString stringWithFormat:@"0%d",i]]; 682 | } 683 | else{ 684 | [minuteArray addObject:[NSString stringWithFormat:@"%d",i]]; 685 | } 686 | } 687 | } 688 | //重置分钟选中行,防止越界。 689 | selectedMinuteRow = selectedHourRow > [minuteArray count] - 1 ? [minuteArray count] - 1 : selectedMinuteRow; 690 | } 691 | -(int)getDaysWithSelectYear:(NSInteger)year andMonth:(NSInteger)month{ 692 | 693 | int totalDay; 694 | if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { 695 | totalDay = 31; 696 | } 697 | else if(month == 2) 698 | { 699 | if (((year % 4 == 0 && year % 100 != 0 ))|| (year % 400 == 0)) { 700 | totalDay = 29; 701 | } 702 | else 703 | { 704 | totalDay = 28; 705 | } 706 | } 707 | else 708 | { 709 | totalDay = 30; 710 | } 711 | return totalDay; 712 | } 713 | #pragma mark 取消 714 | - (void)cancel { 715 | 716 | [self __hideWithAnimation:YES]; 717 | if (_delegate && [_delegate respondsToSelector:@selector(cancleEvent)]) { 718 | [_delegate cancleEvent]; 719 | } 720 | } 721 | 722 | #pragma mark 完成 723 | - (void)completion { 724 | NSDateComponents *dateComponents = [[NSDateComponents alloc]init]; 725 | [dateComponents setYear:[[yearArray objectAtIndex:[datePickerView selectedRowInComponent:0]] integerValue]]; 726 | [dateComponents setMonth:[[monthArray objectAtIndex:[datePickerView selectedRowInComponent:1]] integerValue]]; 727 | [dateComponents setDay:[[dayArray objectAtIndex:[datePickerView selectedRowInComponent:2]] integerValue]]; 728 | if (_datePickerViewShowModel == QBMDatePickerViewShowModelDefalut) { 729 | [dateComponents setHour:[[hourArray objectAtIndex:[datePickerView selectedRowInComponent:3]] integerValue]]; 730 | [dateComponents setMinute:[[minuteArray objectAtIndex:[datePickerView selectedRowInComponent:4]] integerValue]]; 731 | }else if (_datePickerViewShowModel == QBMDatePickerViewShowModelYearMonthDayHour) { 732 | [dateComponents setHour:[[hourArray objectAtIndex:[datePickerView selectedRowInComponent:3]] integerValue]]; 733 | } 734 | 735 | NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 736 | NSDate *selectedDate = [calendar dateFromComponents:dateComponents]; 737 | if (_delegate && [_delegate respondsToSelector:@selector(datePickerView:didSelectDate:)]) { 738 | [_delegate datePickerView:self didSelectDate:selectedDate]; 739 | } 740 | 741 | [self __hideWithAnimation:YES]; 742 | } 743 | 744 | #pragma mark 显示 745 | - (void)__showWithAnimation:(BOOL)animation { 746 | _visible = YES; 747 | 748 | UIView *spView = self.superview; 749 | CGFloat originY = CGRectGetHeight(spView.frame) - CGRectGetHeight(self.frame); 750 | if (animation) { 751 | [UIView animateWithDuration:QBMDURATION animations:^{ 752 | self.frame = CGRectMake(self.frame.origin.x, originY, self.frame.size.width, self.frame.size.height); 753 | }]; 754 | }else { 755 | self.frame = CGRectMake(self.frame.origin.x, originY, self.frame.size.width, self.frame.size.height); 756 | } 757 | 758 | } 759 | 760 | #pragma mark 隐藏 761 | - (void)__hideWithAnimation:(BOOL)animation { 762 | 763 | [UIView animateWithDuration:QBMDURATION animations:^{ 764 | [self removeFromSuperview]; 765 | }]; 766 | } 767 | 768 | #pragma mark 更新但前时间数组中的数据 769 | - (void)updateCurrentDateArray { 770 | //获取当前选中时间。 771 | NSInteger currentYear = [[yearArray objectAtIndex:selectedYearRow] integerValue]; 772 | NSInteger currentMonth = [[monthArray objectAtIndex:selectedMonthRow] integerValue]; 773 | NSInteger currentDay = [[dayArray objectAtIndex:selectedDayRow] integerValue]; 774 | NSInteger currentHour = [[hourArray objectAtIndex:selectedHourRow] integerValue]; 775 | 776 | //更新时间数组中的数据。 777 | [self resetYearArray]; 778 | [self resetMonthArrayWithYear:currentYear]; 779 | [self resetDayArrayWithYear:currentYear month:currentMonth]; 780 | [self resetHourArrayWithYear:currentYear month:currentMonth day:currentDay]; 781 | [self resetMinuteArrayWithYear:currentYear month:currentMonth day:currentDay hour:currentHour]; 782 | } 783 | 784 | #pragma mark - UIPickerViewDelegate, UIPickerViewDataSource 785 | - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { 786 | 787 | switch (_datePickerViewShowModel) { 788 | case QBMDatePickerViewShowModelDefalut: 789 | return 5; 790 | break; 791 | case QBMDatePickerViewShowModelYearMonthDay: 792 | return 3; 793 | break; 794 | case QBMDatePickerViewShowModelYearMonthDayHour: 795 | return 4; 796 | break; 797 | } 798 | } 799 | - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component 800 | { 801 | 802 | switch (component) { 803 | case 0: 804 | return 83*BILIWIDTH; 805 | break; 806 | case 1: 807 | return 60*BILIWIDTH; 808 | break; 809 | case 2: 810 | return 57*BILIWIDTH; 811 | break; 812 | case 3: 813 | return 70*BILIWIDTH; 814 | break; 815 | case 4: 816 | return Screen_width-(83+60+57+70)*BILIWIDTH; 817 | break; 818 | default: 819 | return 0; 820 | break; 821 | } 822 | 823 | 824 | } 825 | - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { 826 | switch (component) { 827 | case 0: 828 | return [yearArray count]; 829 | break; 830 | case 1: 831 | return [monthArray count]; 832 | break; 833 | case 2: 834 | return [dayArray count]; 835 | break; 836 | case 3: 837 | return [hourArray count]; 838 | break; 839 | case 4: 840 | return [minuteArray count]; 841 | break; 842 | default: 843 | return 0; 844 | break; 845 | } 846 | } 847 | - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{ 848 | 849 | return QBMROW_HEIGHT; 850 | } 851 | 852 | - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view 853 | { 854 | UILabel *pickerLabel = (UILabel *)view; 855 | if (pickerLabel == nil) { 856 | CGFloat labelWidth = 0.0; 857 | pickerLabel = [[UILabel alloc]init]; 858 | pickerLabel.backgroundColor = [UIColor clearColor]; 859 | pickerLabel.font = [UIFont systemFontOfSize:16*BILIWIDTH]; 860 | pickerLabel.textColor=[QBMUtil colorWithHexString:@"#313131"]; 861 | pickerLabel.textAlignment = NSTextAlignmentCenter; 862 | switch (_datePickerViewShowModel) { 863 | case QBMDatePickerViewShowModelDefalut: 864 | { 865 | switch (component) { 866 | case 0: 867 | labelWidth=sizeOfYear.width+10*BILIWIDTH; 868 | pickerLabel.frame=CGRectMake(25*BILIWIDTH, 0.0f, labelWidth, QBMROW_HEIGHT); 869 | pickerLabel.textAlignment = NSTextAlignmentRight; 870 | break; 871 | case 1: 872 | labelWidth=sizeOfOther.width+10*BILIWIDTH; 873 | pickerLabel.frame=CGRectMake(20*BILIWIDTH, 0.0f, labelWidth, QBMROW_HEIGHT); 874 | break; 875 | case 2: 876 | labelWidth=sizeOfOther.width+10*BILIWIDTH; 877 | pickerLabel.frame=CGRectMake(20*BILIWIDTH, 0.0f, labelWidth, QBMROW_HEIGHT); 878 | pickerLabel.textAlignment = NSTextAlignmentLeft; 879 | break; 880 | case 3: 881 | labelWidth=sizeOfOther.width+10*BILIWIDTH; 882 | pickerLabel.frame=CGRectMake(60*BILIWIDTH, 0.0f, labelWidth, QBMROW_HEIGHT); 883 | pickerLabel.textAlignment = NSTextAlignmentRight; 884 | break; 885 | case 4: 886 | labelWidth=sizeOfOther.width+10*BILIWIDTH; 887 | pickerLabel.frame=CGRectMake(0.0f, 0.0f, labelWidth, QBMROW_HEIGHT); 888 | pickerLabel.textAlignment = NSTextAlignmentLeft; 889 | break; 890 | default: 891 | break; 892 | } 893 | } 894 | break; 895 | case QBMDatePickerViewShowModelYearMonthDay: 896 | labelWidth = CGRectGetWidth(pickerView.frame) / 3; 897 | pickerLabel.frame=CGRectMake(0.0f, 0.0f, labelWidth, QBMROW_HEIGHT); 898 | break; 899 | case QBMDatePickerViewShowModelYearMonthDayHour: 900 | labelWidth = CGRectGetWidth(pickerView.frame) / 4; 901 | pickerLabel.frame=CGRectMake(0.0f, 0.0f, labelWidth, QBMROW_HEIGHT); 902 | break; 903 | } 904 | } 905 | 906 | switch (component) { 907 | case 0: 908 | 909 | pickerLabel.text = [yearArray objectAtIndex:row]; 910 | break; 911 | case 1: 912 | pickerLabel.text = [monthArray objectAtIndex:row]; 913 | break; 914 | case 2: 915 | pickerLabel.text = [dayArray objectAtIndex:row]; 916 | break; 917 | case 3: 918 | pickerLabel.text = [hourArray objectAtIndex:row]; 919 | break; 920 | case 4: 921 | pickerLabel.text = [minuteArray objectAtIndex:row]; 922 | break; 923 | default: 924 | break; 925 | } 926 | 927 | return pickerLabel; 928 | } 929 | 930 | - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 931 | switch (component) { 932 | case 0: 933 | { 934 | selectedYearRow = row; 935 | 936 | NSInteger selectedYear = [[yearArray objectAtIndex:row] integerValue]; //获取选择的年份。 937 | [self resetMonthArrayWithYear:selectedYear]; //重置月份。 938 | 939 | NSInteger selectedMonth = [[monthArray objectAtIndex:selectedMonthRow] integerValue]; //获取选择的月份。 940 | [self resetDayArrayWithYear:selectedYear month:selectedMonth]; //重置天数。 941 | 942 | if (_datePickerViewShowModel == QBMDatePickerViewShowModelDefalut) { 943 | NSInteger selectedDay = [[dayArray objectAtIndex:selectedDayRow] integerValue]; //获取选择的天数。 944 | [self resetHourArrayWithYear:selectedYear month:selectedMonth day:selectedDay]; //重置小时。 945 | 946 | NSInteger selectedHour = [[hourArray objectAtIndex:selectedHourRow] integerValue]; //获取选择的小时。 947 | [self resetMinuteArrayWithYear:selectedYear month:selectedMonth day:selectedDay hour:selectedHour]; //重置分钟。 948 | 949 | }else if (_datePickerViewShowModel == QBMDatePickerViewShowModelYearMonthDayHour) { 950 | NSInteger selectedDay = [[dayArray objectAtIndex:selectedDayRow] integerValue]; //获取选择的天数。 951 | [self resetHourArrayWithYear:selectedYear month:selectedMonth day:selectedDay]; //重置小时。 952 | } 953 | 954 | [pickerView reloadAllComponents]; 955 | } 956 | break; 957 | case 1: 958 | { 959 | selectedMonthRow = row; 960 | 961 | NSInteger selectedMonth = [[monthArray objectAtIndex:row]integerValue]; 962 | NSInteger selectedYear = [[yearArray objectAtIndex:selectedYearRow] intValue]; 963 | [self resetDayArrayWithYear:selectedYear month:selectedMonth]; //重置天数 964 | 965 | if (_datePickerViewShowModel == QBMDatePickerViewShowModelDefalut) { 966 | NSInteger selectedDay = [[dayArray objectAtIndex:selectedDayRow] integerValue]; //获取选择的天数。 967 | [self resetHourArrayWithYear:selectedYear month:selectedMonth day:selectedDay]; //重置小时。 968 | 969 | NSInteger selectedHour = [[hourArray objectAtIndex:selectedHourRow] integerValue]; //获取选择的小时。 970 | [self resetMinuteArrayWithYear:selectedYear month:selectedMonth day:selectedDay hour:selectedHour]; //重置分钟。 971 | 972 | }else if (_datePickerViewShowModel == QBMDatePickerViewShowModelYearMonthDayHour) { 973 | NSInteger selectedDay = [[dayArray objectAtIndex:selectedDayRow] integerValue]; //获取选择的天数。 974 | [self resetHourArrayWithYear:selectedYear month:selectedMonth day:selectedDay]; //重置小时。 975 | } 976 | 977 | [pickerView reloadAllComponents]; 978 | } 979 | break; 980 | case 2: 981 | { 982 | selectedDayRow = row; 983 | 984 | 985 | NSInteger selectedDay = [[dayArray objectAtIndex:row] integerValue]; 986 | NSInteger selectedYear = [[yearArray objectAtIndex:selectedYearRow] integerValue]; 987 | NSInteger selectedMonth = [[monthArray objectAtIndex:selectedMonthRow] integerValue]; 988 | if (_datePickerViewShowModel == QBMDatePickerViewShowModelDefalut) { 989 | [self resetHourArrayWithYear:selectedYear month:selectedMonth day:selectedDay]; //重置小时。 990 | 991 | NSInteger selectedHour = [[hourArray objectAtIndex:selectedHourRow] integerValue]; //获取选择的小时。 992 | [self resetMinuteArrayWithYear:selectedYear month:selectedMonth day:selectedDay hour:selectedHour]; //重置分钟。 993 | 994 | }else if (_datePickerViewShowModel == QBMDatePickerViewShowModelYearMonthDayHour) { 995 | [self resetHourArrayWithYear:selectedYear month:selectedMonth day:selectedDay]; //重置小时。 996 | } 997 | 998 | [pickerView reloadAllComponents]; 999 | } 1000 | break; 1001 | case 3: 1002 | { 1003 | selectedHourRow = row; 1004 | 1005 | NSInteger selectedHour = [[hourArray objectAtIndex:row] integerValue]; 1006 | NSInteger selectedYear = [[yearArray objectAtIndex:selectedYearRow] integerValue]; 1007 | NSInteger selectedMonth = [[monthArray objectAtIndex:selectedMonthRow] integerValue]; 1008 | NSInteger selectedDay = [[dayArray objectAtIndex:selectedDayRow] integerValue]; 1009 | if (_datePickerViewShowModel == QBMDatePickerViewShowModelDefalut) { 1010 | [self resetMinuteArrayWithYear:selectedYear month:selectedMonth day:selectedDay hour:selectedHour]; //重置分钟。 1011 | 1012 | } 1013 | 1014 | [pickerView reloadAllComponents]; 1015 | } 1016 | break; 1017 | case 4: 1018 | break; 1019 | default: 1020 | break; 1021 | } 1022 | } 1023 | 1024 | #pragma mark - Setter 1025 | - (void)setMinYear:(NSInteger)minYear { 1026 | NSAssert(minYear < _maxYear, @"最小年份必须小于最大年份!"); 1027 | 1028 | _minYear = minYear; 1029 | 1030 | [self resetYearArray]; 1031 | [datePickerView reloadAllComponents]; 1032 | } 1033 | 1034 | - (void)setMaxYear:(NSInteger)maxYear { 1035 | NSAssert(maxYear > _minYear, @"最大年份必须大于最小年份!"); 1036 | NSAssert(_datePickerViewDateRangeModel == QBMDatePickerViewDateRangeModelCustom, @"当前模式下只允许显示当前系统最大时间,所以不允许设置最大年份!"); 1037 | 1038 | //更新最大值。 1039 | _maxYear = maxYear; 1040 | 1041 | [self updateCurrentDateArray]; 1042 | [datePickerView reloadAllComponents]; 1043 | } 1044 | 1045 | - (void)setDatePickerViewShowModel:(QBMDatePickerViewShowModel)datePickerViewShowModel { 1046 | _datePickerViewShowModel = datePickerViewShowModel; 1047 | [datePickerView reloadAllComponents]; 1048 | 1049 | } 1050 | 1051 | - (void)setDatePickerViewDateRangeModel:(QBMDatePickerViewDateRangeModel)datePickerViewDateRangeModel { 1052 | QBMDatePickerViewDateRangeModel tempModel = datePickerViewDateRangeModel; 1053 | _datePickerViewDateRangeModel = datePickerViewDateRangeModel; 1054 | 1055 | if (tempModel == QBMDatePickerViewDateRangeModelCurrent) { 1056 | //更新时间最大值为当前系统时间。 1057 | NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 1058 | NSCalendarUnit calendarUnit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute; 1059 | NSDateComponents *currentDateComponents = [calendar components:calendarUnit fromDate:[NSDate date]]; 1060 | 1061 | _maxYear = [currentDateComponents year]; 1062 | maxMonth = [currentDateComponents month]; 1063 | maxDay = [currentDateComponents day]; 1064 | maxHour = [currentDateComponents hour]; 1065 | maxMinute = [currentDateComponents minute]; 1066 | 1067 | }else if (tempModel == QBMDatePickerViewDateRangeModelCustom) { 1068 | //年份不变,其它更新为最大值。 1069 | maxMonth = 12; 1070 | maxDay = 31; 1071 | maxHour = 23; 1072 | maxMinute = 59; 1073 | } 1074 | 1075 | [self updateCurrentDateArray]; 1076 | [datePickerView reloadAllComponents]; 1077 | } 1078 | @end 1079 | 1080 | 1081 | -------------------------------------------------------------------------------- /Source/QBMDefine/QBMDefine.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBMDefine.h 3 | // WeexEros 4 | // 5 | // Created by qbm_ios on 2018/5/24. 6 | // Copyright © 2018年 qbm Company. All rights reserved. 7 | 8 | 9 | #import 10 | #define Screen_width [UIScreen mainScreen].bounds.size.width 11 | #define Screen_height [UIScreen mainScreen].bounds.size.height 12 | #define kDevice_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO) 13 | #define BILI ([UIScreen mainScreen].bounds.size.height==812?734/667.0:[UIScreen mainScreen].bounds.size.height/667.0) 14 | #define BILIWIDTH ([UIScreen mainScreen].bounds.size.width/375.0) 15 | -------------------------------------------------------------------------------- /Source/QBMTool/QBMUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIUtil.h 3 | // WeexEros 4 | // 5 | // Created by qbm_ios on 2018/5/24. 6 | // Copyright © 2018年 qbm Company. All rights reserved. 7 | 8 | #import 9 | #import 10 | 11 | @interface QBMUtil : NSObject 12 | + (UIColor *) colorWithHexString: (NSString *) stringToConvert; 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /Source/QBMTool/QBMUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBMUtil.m 3 | // WeexEros 4 | // 5 | // Created by qbm_ios on 2018/5/24. 6 | // Copyright © 2018年 qbm Company. All rights reserved. 7 | 8 | #import "QBMUtil.h" 9 | @implementation QBMUtil 10 | 11 | + (UIColor *) colorWithHexString: (NSString *) stringToConvert 12 | { 13 | NSString *cString = [[stringToConvert stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; 14 | 15 | // String should be 6 or 8 characters 16 | if ([cString length] < 6) return [UIColor blackColor]; 17 | 18 | // strip 0X if it appears 19 | if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; 20 | if ([cString hasPrefix:@"#"]) cString = [cString substringFromIndex:1]; 21 | if ([cString length] != 6) return [UIColor blackColor]; 22 | // Separate into r, g, b substrings 23 | NSRange range; 24 | range.location = 0; 25 | range.length = 2; 26 | NSString *rString = [cString substringWithRange:range]; 27 | 28 | range.location = 2; 29 | NSString *gString = [cString substringWithRange:range]; 30 | 31 | range.location = 4; 32 | NSString *bString = [cString substringWithRange:range]; 33 | 34 | // Scan values 35 | unsigned int r, g, b; 36 | [[NSScanner scannerWithString:rString] scanHexInt:&r]; 37 | [[NSScanner scannerWithString:gString] scanHexInt:&g]; 38 | [[NSScanner scannerWithString:bString] scanHexInt:&b]; 39 | 40 | return [UIColor colorWithRed:((float) r / 255.0f) 41 | green:((float) g / 255.0f) 42 | blue:((float) b / 255.0f) 43 | alpha:1.0f]; 44 | } 45 | @end 46 | 47 | -------------------------------------------------------------------------------- /demo/dateTimePicker.vue: -------------------------------------------------------------------------------- 1 | 20 | 125 | 126 | --------------------------------------------------------------------------------