iOS-时间选择器
2019獨角獸企業重金招聘Python工程師標準>>>
前言
項目開發中常會有時間選擇的需求,但是蘋果系統的時間選擇控件交互邏輯不太友好,換句話說就是不能滿足我們開發的需求,一般常用的是需要選擇開始時間和結束時間進行數據篩選,因此這個自定義控件主要往這個方向的封裝,但是大概思路應該是這樣的。
?
一、設計的思路:采用分段控件區分當前選擇的時間是開始時間還是結束時間,然后判斷兩個時間的合法性,最后再判斷底部的“確定”按鈕是否可點擊;回調支持delegate與block回調,若兩者都設置,會優先采用delegate回調。showTopSegmentedControl屬性,用于控制是否顯示頂部的segmentedControl控件,默認是顯示的,加上該屬性主要是滿足有單個時間選擇的需求。
#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;@endtypedef 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?
二、點擊時間選擇按鈕,自下而上彈出控件。
#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?
?
三、最后
DYLDatePickerView中有幾個工具類沒有給出來,其實也不是很復雜的內容,僅僅封裝了一些事件判斷邏輯以及創建控件的幫助管理器,DYLDatePickerView的github下載地址。
?
轉載于:https://my.oschina.net/u/1450995/blog/541480
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
- 上一篇: 每日更新
- 下一篇: spring+mybatis+atomi