前言git
項目開發中常會有時間選擇的需求,可是蘋果系統的時間選擇控件交互邏輯不太友好,換句話說就是不能知足咱們開發的需求,通常經常使用的是須要選擇開始時間和結束時間進行數據篩選,所以這個自定義控件主要往這個方向的封裝,可是大概思路應該是這樣的。github
1、設計的思路:採用分段控件區分當前選擇的時間是開始時間仍是結束時間,而後判斷兩個時間的合法性,最後再判斷底部的「肯定」按鈕是否可點擊;回調支持delegate與block回調,若二者都設置,會優先採用delegate回調。showTopSegmentedControl屬性,用於控制是否顯示頂部的segmentedControl控件,默認是顯示的,加上該屬性主要是知足有單個時間選擇的需求。ide
#import <UIKit/UIKit.h> @class DYLDatePickerView; typedef NS_ENUM(NSInteger, DYLDateType) { DYLDateTypeStartDate = 0, DYLDateTypeEndDate }; @protocol DYLDatePickerViewDelegate <NSObject> @optional - (void)callback:(DYLDatePickerView *)datePickerView beginDateStr:(NSString *)beginDateStr endDateStr:(NSString *)endDateStr; @end typedef void(^CallbackCompleteBlock)(NSString *beginDateStr, NSString *endDateStr); @interface DYLDatePickerView : UIView @property (assign, nonatomic) NSInteger maximumIntervalDay; @property (strong, nonatomic) NSString *minLimitDate; @property (assign, nonatomic) NSTimeInterval duration; //是否顯示頂部segmentedControl @property (assign, nonatomic) BOOL showTopSegmentedControl; @property (weak, nonatomic) id<DYLDatePickerViewDelegate> delegate; @property (copy, nonatomic) CallbackCompleteBlock completeBlock; - (void)show; - (void)hide; @end #import "DYLDatePickerView.h" #import "UIUtils.h" #import <Masonry.h> #import "DYLDatePickerManager.h" #define mScreenWidth ([UIScreen mainScreen].bounds.size.width) #define mScreenHeight ([UIScreen mainScreen].bounds.size.height) #define mEmptyStr @"" #define mBlueColor [UIColor colorWithRed:50.0/255.0 green:162.0/255.0 blue:248.0/255.0 alpha:1.0] #define mGrayColor [UIColor colorWithRed:165/255.0 green:165/255.0 blue:165/255.0 alpha:1.0] static CGFloat const DYLDatePickerAnimationDuration = 0.25; static CGFloat const DYLDatePickerButtonHeight = 30; @interface DYLDatePickerView () @property (strong, nonatomic) UIView *bgView; @property (strong, nonatomic) UISegmentedControl *dateSegmentView; @property (assign, nonatomic) DYLDateType dateType; @property (strong, nonatomic) UIView *sureDateView; @property (strong, nonatomic) UIButton *sureDateButton; @property (strong, nonatomic) UILabel *tipLabel; @property (strong, nonatomic) UIDatePicker *datePicker; @property (strong, nonatomic) UIView *bottomView; @property (strong, nonatomic) UIButton *completeRefreshButton; @property (copy, nonatomic) NSString *beginDateStr; @property (copy, nonatomic) NSString *endDateStr; @end @implementation DYLDatePickerView #pragma mark - lifeCicle - (instancetype)init { self = [super init]; if (self) { self.frame = CGRectMake(0, mScreenHeight, mScreenWidth, 320); self.backgroundColor = [UIColor whiteColor]; [self commonInit]; [self createBgView]; [self createDatePickerView]; [self configDatePickerView]; } return self; } #pragma mark - Private Method - (void)commonInit { self.duration = DYLDatePickerAnimationDuration; self.showTopSegmentedControl = YES; } - (void)createBgView { self.bgView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.bgView.hidden = YES; self.bgView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3]; UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)]; [self.bgView addGestureRecognizer:tapGesture]; } - (void)createDatePickerView { self.dateSegmentView = [UIUtils segmentViewWithTintColor:mBlueColor items:@[@"開始時間", @"結束時間"]]; self.dateSegmentView.selectedSegmentIndex = 0; [self.dateSegmentView addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged]; [self addSubview:self.dateSegmentView]; self.sureDateView = [UIUtils viewWithBackgroudColor:[UIColor whiteColor]]; [self addSubview:self.sureDateView]; self.sureDateButton = [UIUtils buttonWithTitle:@"肯定" titleColor:mBlueColor fontSize:15.f cornerRadius:0.f]; [self.sureDateButton addTarget:self action:@selector(sureDateButtonClick:) forControlEvents:UIControlEventTouchUpInside]; [self.sureDateView addSubview:self.sureDateButton]; self.tipLabel = [UIUtils labelWithTextColor:mGrayColor textAlignment:NSTextAlignmentLeft text:@"開始選擇時間" fontSize:14.f]; [self.sureDateView addSubview:self.tipLabel]; self.datePicker = [UIUtils datePickerWithLocale:@"zh-CN" datePickerMode:UIDatePickerModeDate]; [self addSubview:self.datePicker]; self.bottomView = [UIUtils viewWithBackgroudColor:[UIColor whiteColor]]; [self addSubview:self.bottomView]; self.completeRefreshButton = [UIUtils buttonWithBackgroundColor:mBlueColor titleColor:[UIColor whiteColor] selectedColor:[UIColor lightGrayColor] title:@"肯定" fontSize:15.f cornerRadius:3.f]; self.completeRefreshButton.enabled = NO; [self.completeRefreshButton addTarget:self action:@selector(callback) forControlEvents:UIControlEventTouchUpInside]; [self.bottomView addSubview:self.completeRefreshButton]; } - (void)configDatePickerView { [self.dateSegmentView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(@15); make.width.equalTo(@200); make.height.equalTo(@(DYLDatePickerButtonHeight)); make.centerX.equalTo(self); }]; [self.sureDateView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.dateSegmentView.mas_bottom).offset(15); make.left.and.right.equalTo(self); make.height.equalTo(@40); }]; [self.sureDateButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(@0); make.right.equalTo(self.mas_right); make.width.equalTo(@60); make.bottom.equalTo(self.sureDateView.mas_bottom); }]; [self.tipLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(@0); make.left.equalTo(@15); make.right.equalTo(self.sureDateButton.mas_left).offset(-15); make.bottom.equalTo(self.sureDateView.mas_bottom); }]; [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(@60); make.left.and.right.equalTo(self); make.bottom.equalTo(self); }]; [self.datePicker mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.sureDateView.mas_bottom).offset(15); make.left.and.right.equalTo(self); make.bottom.equalTo(self.bottomView.mas_top); }]; [self.completeRefreshButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.mas_left).offset(50); make.right.equalTo(self.mas_right).offset(-50); make.height.mas_equalTo(35); make.centerY.equalTo(self.bottomView.mas_centerY); }]; } - (void)setMinLimitDate:(NSString *)minLimitDate { _minLimitDate = minLimitDate; self.datePicker.minimumDate = [[DYLDatePickerManager sharedManager].formatter dateFromString:minLimitDate]; } - (void)setShowTopSegmentedControl:(BOOL)showTopSegmentedControl { _showTopSegmentedControl = showTopSegmentedControl; if (showTopSegmentedControl && self.dateSegmentView.isHidden) { self.dateSegmentView.hidden = !showTopSegmentedControl; [self.sureDateView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.dateSegmentView.mas_bottom).offset(15); make.left.and.right.equalTo(self); make.height.equalTo(@40); }]; } else { if (!showTopSegmentedControl && !self.dateSegmentView.isHidden) { self.dateSegmentView.hidden = !showTopSegmentedControl; [self.sureDateView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.and.left.and.right.equalTo(self); make.height.equalTo(@40); }]; } } } - (void)sureDateButtonClick:(UIButton *)sender { switch (_dateType) { case DYLDateTypeStartDate: { self.beginDateStr = [[DYLDatePickerManager sharedManager].formatter stringFromDate:self.datePicker.date]; break; } case DYLDateTypeEndDate: { self.endDateStr = [[DYLDatePickerManager sharedManager].formatter stringFromDate:self.datePicker.date]; break; } default: break; } [self refreshDatePickerView]; } - (void)segmentAction:(UISegmentedControl *)sender { self.dateType = sender.selectedSegmentIndex; switch (_dateType) { case DYLDateTypeStartDate: { if (_beginDateStr) { [self.datePicker setDate:[[DYLDatePickerManager sharedManager].formatter dateFromString:_beginDateStr] animated:YES]; } break; } case DYLDateTypeEndDate: { if (_endDateStr) { [self.datePicker setDate:[[DYLDatePickerManager sharedManager].formatter dateFromString:_endDateStr] animated:YES]; } break; } default: break; } } - (void)refreshDatePickerView { NSString *beginDateStr = _beginDateStr ? _beginDateStr : mEmptyStr; NSString *endDateStr = _endDateStr ? _endDateStr : mEmptyStr; if (self.showTopSegmentedControl) { self.tipLabel.text = [NSString stringWithFormat:@"%@,%@", beginDateStr, endDateStr]; self.completeRefreshButton.enabled = _beginDateStr && _endDateStr; } else { self.tipLabel.text = beginDateStr; self.completeRefreshButton.enabled = _beginDateStr || _endDateStr; } if (self.completeRefreshButton.enabled) { if (self.showTopSegmentedControl) { NSInteger distanceDays = [[DYLDatePickerManager sharedManager] distanceFrom:_beginDateStr to:_endDateStr]; if (distanceDays > self.maximumIntervalDay) { self.completeRefreshButton.enabled = NO; [self.completeRefreshButton setTitle:@"超過規定時間間隔" forState:UIControlStateDisabled]; } else { if (distanceDays < 0) { self.completeRefreshButton.enabled = NO; [self.completeRefreshButton setTitle:@"開始時間須小於結束時間" forState:UIControlStateDisabled]; } else { [self.completeRefreshButton setTitle:@"肯定" forState:UIControlStateNormal]; } } } } } - (void)callback { if ([self.delegate respondsToSelector:@selector(callback:beginDateStr:endDateStr:)]) { [self.delegate callback:self beginDateStr:self.beginDateStr endDateStr:self.endDateStr]; } else { if (self.completeBlock) { self.completeBlock(self.beginDateStr, self.endDateStr); } } } - (void)show { UIWindow *window = [UIApplication sharedApplication].keyWindow; [window addSubview:self.bgView]; [window addSubview:self]; } - (void)didMoveToWindow { if (self.window) { [UIView animateWithDuration:self.duration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.bgView.hidden = NO; CGRect newFrame = self.frame; newFrame.origin.y = mScreenHeight - CGRectGetHeight(self.frame); self.frame = newFrame; } completion:^(BOOL finished) { if (finished) { } }]; } } - (void)hide { [UIView animateWithDuration:self.duration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ CGRect newFrame = self.frame; newFrame.origin.y = mScreenHeight; self.frame = newFrame; } completion:^(BOOL finished) { if (finished) { self.bgView.hidden = YES; [self.bgView removeFromSuperview]; [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; [self removeFromSuperview]; } }]; } @end
2、點擊時間選擇按鈕,自下而上彈出控件。工具
#import "ViewController.h" #import "DYLDatePickerView.h" @interface ViewController () <DYLDatePickerViewDelegate> @property (strong, nonatomic) UIButton *showDateButton; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.view.backgroundColor = [UIColor whiteColor]; self.showDateButton = [UIButton buttonWithType:UIButtonTypeCustom]; self.showDateButton.frame = CGRectMake(20, 100, 240, 40); [self.showDateButton setTitle:@"時間" forState:UIControlStateNormal]; [self.showDateButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [self.showDateButton addTarget:self action:@selector(handleAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.showDateButton]; } - (void)handleAction:(UIButton *)sender { DYLDatePickerView *datePickerView = [[DYLDatePickerView alloc] init]; datePickerView.maximumIntervalDay = 90; datePickerView.minLimitDate = @"2014-04-01"; datePickerView.delegate = self; __weak typeof(self) weakSelf = self; datePickerView.completeBlock = ^(NSString *beginDateStr, NSString *endDateStr) { [weakSelf.showDateButton setTitle:[NSString stringWithFormat:@"%@-%@", beginDateStr, endDateStr] forState:UIControlStateNormal]; }; [datePickerView show]; } // 優先執行delegate邏輯 - (void)callback:(DYLDatePickerView *)datePickerView beginDateStr:(NSString *)beginDateStr endDateStr:(NSString *)endDateStr { [self.showDateButton setTitle:[NSString stringWithFormat:@"%@-%@", beginDateStr, endDateStr] forState:UIControlStateNormal]; } @end
3、最後atom
DYLDatePickerView中有幾個工具類沒有給出來,其實也不是很複雜的內容,僅僅封裝了一些事件判斷邏輯以及建立控件的幫助管理器,DYLDatePickerView的github下載地址。設計