iOS-时间选择器

前言

项目开发中常会有时间选择的需求,但是苹果系统的时间选择控件交互逻辑不太友好,换句话说就是不能满足我们开发的需求,一般常用的是需要选择开始时间和结束时间进行数据筛选,因此这个自定义控件主要往这个方向的封装,但是大概思路应该是这样的。

 

一、设计的思路:采用分段控件区分当前选择的时间是开始时间还是结束时间,然后判断两个时间的合法性,最后再判断底部的“确定”按钮是否可点击;回调支持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;

@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

 

二、点击时间选择按钮,自下而上弹出控件。

#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值