iOS-時間選擇器

前言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下載地址。設計

相關文章
相關標籤/搜索