前言
仿支付宝的日期选择器。在支付宝账单里面有根据日期进行筛选功能,项目中正好要用到,参考BRDatePickerView的数据源和Date分类。以此做下记录
1.效果图如下:
2.实现
.h代码
// 日/月 选择
#import "UIBaseViewController.h"
NS_ASSUME_NONNULL_BEGIN
typedef void(^monthDayBlock)(NSInteger dateType,NSString *startTime,NSString *endTime);
@interface ChooseDateViewController : UIBaseViewController
@property (copy,nonatomic)monthDayBlock block;
@end
NS_ASSUME_NONNULL_END
.m代码
#import "ChooseDateViewController.h"
#import "YearDayModel.h"
/// 弹出日期类型
typedef NS_ENUM(NSInteger, MLDatePickerMode) {
// 年月
MLDatePickerModeYM = 0, // yyyy-MM
// 年月日
MLDatePickerModeYMD = 1, // yyyy-MM-dd
};
@interface ChooseDateViewController ()<UITextFieldDelegate,UIPickerViewDelegate,UIPickerViewDataSource>{
// 记录 年、月、日当前选择的位置
NSInteger _yearIndex;
NSInteger _monthIndex;
NSInteger _dayIndex;
}
@property (weak, nonatomic) IBOutlet UIButton *chooseBtn;//完成按钮
@property (weak, nonatomic) IBOutlet UIView *dayView; //年月日view
@property (weak, nonatomic) IBOutlet UIView *monthView;//年月view
@property (weak, nonatomic) IBOutlet UITextField *startDayTF;//按日选择 开始
@property (weak, nonatomic) IBOutlet UITextField *endDayTF;//按日选择 结束
@property (weak, nonatomic) IBOutlet UITextField *monthTF;//按月选择
@property (weak, nonatomic) IBOutlet UIPickerView *YMpickView;//年月
@property (assign,nonatomic)NSInteger tag;//记录年月日的开始时间和结束时间TF
/// 日期存储数组
@property(nonatomic, strong) NSArray *yearArr;
@property(nonatomic, strong) NSArray *monthArr;
@property(nonatomic, strong) NSArray *dayArr;
/** 显示类型 */
@property (nonatomic, assign) MLDatePickerMode showType;
/** 限制最小日期 */
@property (nonatomic, strong) NSDate *minLimitDate;
/** 限制最大日期 */
@property (nonatomic, strong) NSDate *maxLimitDate;
/** 当前选择的日期 */
@property (nonatomic, strong) NSDate *selectDate;
/** 选择的日期的格式 */
@property (nonatomic, strong) NSString *selectDateFormatter;
@end
@implementation ChooseDateViewController
- (void)viewDidLoad{
[super viewDidLoad];
self.navBar.titleLabel.text = @"选择时间";
self.view.backgroundColor = [UIColor whiteColor];
self.YMpickView.showsSelectionIndicator = YES;
//设置UIPickerView的代理
self.YMpickView.delegate =self;
self.YMpickView.dataSource =self;
// 设置子视图的大小随着父视图变化
self.YMpickView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
self.monthTF.delegate = self;
self.endDayTF.delegate = self;
self.startDayTF.delegate = self;
self.tag = self.monthTF.tag = 100;
self.startDayTF.tag = 101;
self.endDayTF.tag = 102;
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
//界面出现时再获取数据源否则不自动滚动
//默认选择月
self.showType = MLDatePickerModeYM;
[self setUP];
}
#pragma mark - setUP
- (void)setUP{
self.dayView.hidden = (self.showType == MLDatePickerModeYM);
self.monthView.hidden = !(self.showType == MLDatePickerModeYM);
[self setupSelectDateFormatter:self.showType];
[self setupMinMaxValue:self.showType];
// 不设置默认日期,就默认选中今天的日期
NSString *defaultSelValue = [NSDate br_getDateString:[NSDate date] format:self.selectDateFormatter];
self.selectDate = [NSDate br_getDate:defaultSelValue format:self.selectDateFormatter];
[self initDefaultDateArray];
[self scrollToSelectDate:self.selectDate animated:NO];
}
- (void)setupSelectDateFormatter:(MLDatePickerMode)model {
switch (model) {
case MLDatePickerModeYM:
{
self.selectDateFormatter = @"yyyy-MM";
}
break;
case MLDatePickerModeYMD:
{
self.selectDateFormatter = @"yyyy-MM-dd";
}
break;
default:
break;
}
}
- (void)setupMinMaxValue:(MLDatePickerMode)model {
switch (model) {
case MLDatePickerModeYM:
{
self.minLimitDate = [NSDate br_setYear:2015 month:1];
NSDate *now = [NSDate date];
self.maxLimitDate = [NSDate br_setYear:now.br_year month:now.br_month];
}
break;
case MLDatePickerModeYMD:
{
self.minLimitDate = [NSDate br_setYear:2015 month:1 day:1];
NSDate *now = [NSDate date];
self.maxLimitDate = [NSDate br_setYear:now.br_year month:now.br_month day:now.br_day];
}
break;
default:
break;
}
}
#pragma mark - 设置日期数据源数组
- (void)initDefaultDateArray {
// 1. 设置 yearArr 数组
[self setupYearArr];
// 2.设置 monthArr 数组
[self setupMonthArr:self.selectDate.br_year];
// 3.设置 dayArr 数组
[self setupDayArr:self.selectDate.br_year month:self.selectDate.br_month];
//刷新界面
[self.YMpickView reloadAllComponents];
// 根据 默认选择的日期 计算出 对应的索引
_yearIndex = self.selectDate.br_year - self.minLimitDate.br_year;
_monthIndex = self.selectDate.br_month - ((_yearIndex == 0) ? self.minLimitDate.br_month : 1);
_dayIndex = self.selectDate.br_day - ((_yearIndex == 0 && _monthIndex == 0) ? self.minLimitDate.br_day : 1);
}
#pragma mark - 更新日期数据源数组
- (void)updateDateArray {
NSInteger year = [self.yearArr[_yearIndex] integerValue];
// 1.设置 monthArr 数组
[self setupMonthArr:year];
// 更新索引:防止更新 monthArr 后数组越界
_monthIndex = (_monthIndex > self.monthArr.count - 1) ? (self.monthArr.count - 1) : _monthIndex;
NSInteger month = [self.monthArr[_monthIndex] integerValue];
// 2.设置 dayArr 数组
[self setupDayArr:year month:month];
// 更新索引:防止更新 dayArr 后数组越界
_dayIndex = (_dayIndex > self.dayArr.count - 1) ? (self.dayArr.count - 1) : _dayIndex;
}
// 设置 yearArr 数组
- (void)setupYearArr {
NSMutableArray *tempArr = [NSMutableArray array];
for (NSInteger i = self.minLimitDate.br_year; i <= self.maxLimitDate.br_year; i++) {
[tempArr addObject:[@(i) stringValue]];
}
self.yearArr = [tempArr copy];
}
// 设置 monthArr 数组
- (void)setupMonthArr:(NSInteger)year {
NSInteger startMonth = 1;
NSInteger endMonth = 12;
if (year == self.minLimitDate.br_year) {
startMonth = self.minLimitDate.br_month;
}
if (year == self.maxLimitDate.br_year) {
endMonth = self.maxLimitDate.br_month;
}
NSMutableArray *tempArr = [NSMutableArray arrayWithCapacity:(endMonth - startMonth + 1)];
for (NSInteger i = startMonth; i <= endMonth; i++) {
[tempArr addObject:[@(i) stringValue]];
}
self.monthArr = [tempArr copy];
}
// 设置 dayArr 数组
- (void)setupDayArr:(NSInteger)year month:(NSInteger)month {
NSInteger startDay = 1;
NSInteger endDay = [NSDate br_getDaysInYear:year month:month];
if (year == self.minLimitDate.br_year && month == self.minLimitDate.br_month) {
startDay = self.minLimitDate.br_day;
}
if (year == self.maxLimitDate.br_year && month == self.maxLimitDate.br_month) {
endDay = self.maxLimitDate.br_day;
}
NSMutableArray *tempArr = [NSMutableArray array];
for (NSInteger i = startDay; i <= endDay; i++) {
[tempArr addObject:[NSString stringWithFormat:@"%zi",i]];
}
self.dayArr = [tempArr copy];
}
#pragma mark - 滚动到指定的时间位置
- (void)scrollToSelectDate:(NSDate *)selectDate animated:(BOOL)animated {
// 根据 当前选择的日期 计算出 对应的索引
NSInteger yearIndex = selectDate.br_year - self.minLimitDate.br_year;
NSInteger monthIndex = selectDate.br_month - ((yearIndex == 0) ? self.minLimitDate.br_month : 1);
NSInteger dayIndex = selectDate.br_day - ((yearIndex == 0 && monthIndex == 0) ? self.minLimitDate.br_day : 1);
NSArray *indexArr = [NSArray array];
if (self.showType == MLDatePickerModeYMD) {
indexArr = @[@(yearIndex), @(monthIndex), @(dayIndex)];
} else if (self.showType == MLDatePickerModeYM) {
indexArr = @[@(yearIndex), @(monthIndex)];
}
for (NSInteger i = 0; i < indexArr.count; i++) {
[self.YMpickView selectRow:[indexArr[i] integerValue] inComponent:i animated:animated];
}
}
#pragma mark - UIPickerViewDataSource
// 1.指定pickerview有几个表盘(几列)
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
if (self.showType == MLDatePickerModeYMD) {
return 3;
} else if (self.showType == MLDatePickerModeYM) {
return 2;
}
return 0;
}
// 2.指定每个表盘上有几行数据
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSArray *rowsArr = [NSArray array];
if (self.showType == MLDatePickerModeYMD) {
rowsArr = @[@(self.yearArr.count), @(self.monthArr.count), @(self.dayArr.count)];
} else if (self.showType == MLDatePickerModeYM) {
rowsArr = @[@(self.yearArr.count), @(self.monthArr.count)];
}
return [rowsArr[component] integerValue];
}
#pragma mark - UIPickerViewDelegate
// 3.设置 pickerView 的 显示内容
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view {
// 设置分割线的颜色
((UIView *)[pickerView.subviews objectAtIndex:1]).backgroundColor = [UIColor colorWithRed:195/255.0 green:195/255.0 blue:195/255.0 alpha:1.0f];
((UIView *)[pickerView.subviews objectAtIndex:2]).backgroundColor = [UIColor colorWithRed:195/255.0 green:195/255.0 blue:195/255.0 alpha:1.0f];
UILabel *label = (UILabel *)view;
if (!label) {
label = [[UILabel alloc]init];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentCenter;
label.font = font(24);
// 字体自适应属性
label.adjustsFontSizeToFitWidth = YES;
// 自适应最小字体缩放比例
label.minimumScaleFactor = 0.5f;
}
// 给选择器上的label赋值
[self setDateLabelText:label component:component row:row];
return label;
}
// 4.选中时回调的委托方法,在此方法中实现省份和城市间的联动
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
// 获取滚动后选择的日期
self.selectDate = [self getDidSelectedDate:component row:row];
NSString *selectDateValue = [NSDate br_getDateString:self.selectDate format:self.selectDateFormatter];
switch (self.showType) {
case MLDatePickerModeYMD:{
if(self.tag == 101){
self.startDayTF.text = selectDateValue;
}else if(self.tag == 102){
self.endDayTF.text = selectDateValue;
}
}
break;
case MLDatePickerModeYM:{
self.monthTF.text = selectDateValue;
}
break;
default:
break;
}
}
// 设置行高
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component {
return 35.0f;
}
- (void)setDateLabelText:(UILabel *)label component:(NSInteger)component row:(NSInteger)row {
if (self.showType == MLDatePickerModeYMD) {
if (component == 0) {
label.text = [NSString stringWithFormat:@"%@年", self.yearArr[row]];
} else if (component == 1) {
label.text = [NSString stringWithFormat:@"%@月", self.monthArr[row]];
} else if (component == 2) {
label.text = [NSString stringWithFormat:@"%@日", self.dayArr[row]];
}
} else if (self.showType == MLDatePickerModeYM) {
if (component == 0) {
label.text = [NSString stringWithFormat:@"%@年", self.yearArr[row]];
} else if (component == 1) {
label.text = [NSString stringWithFormat:@"%@月", self.monthArr[row]];
}
}
}
- (NSDate *)getDidSelectedDate:(NSInteger)component row:(NSInteger)row {
NSString *selectDateValue = nil;
if (self.showType == MLDatePickerModeYMD) {
if (component == 0) {
_yearIndex = row;
[self updateDateArray];
[self.YMpickView reloadComponent:1];
[self.YMpickView reloadComponent:2];
} else if (component == 1) {
_monthIndex = row;
[self updateDateArray];
[self.YMpickView reloadComponent:2];
} else if (component == 2) {
_dayIndex = row;
}
selectDateValue = [NSString stringWithFormat:@"%@-%02ld-%02ld", self.yearArr[_yearIndex], [self.monthArr[_monthIndex] integerValue], [self.dayArr[_dayIndex] integerValue]];
} else if (self.showType == MLDatePickerModeYM) {
if (component == 0) {
_yearIndex = row;
[self updateDateArray];
[self.YMpickView reloadComponent:1];
} else if (component == 1) {
_monthIndex = row;
}
selectDateValue = [NSString stringWithFormat:@"%@-%02ld", self.yearArr[_yearIndex], [self.monthArr[_monthIndex] integerValue]];
}
return [NSDate br_getDate:selectDateValue format:self.selectDateFormatter];
}
#pragma mark - getter 方法
- (NSArray *)yearArr {
if (!_yearArr) {
_yearArr = [NSArray array];
}
return _yearArr;
}
- (NSArray *)monthArr {
if (!_monthArr) {
_monthArr = [NSArray array];
}
return _monthArr;
}
- (NSArray *)dayArr {
if (!_dayArr) {
_dayArr = [NSArray array];
}
return _dayArr;
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
self.tag = textField.tag;
return NO; // 当前 textField 不可编辑,可以响应点击事件
}
//按日/月切换
- (IBAction)change:(UIButton *)sender {
if (self.showType == MLDatePickerModeYM) {
self.showType = MLDatePickerModeYMD;
}else{
self.showType = MLDatePickerModeYM;
}
[self setUP];
NSString *str = (self.showType == MLDatePickerModeYM)?@"按月选择":@"按日选择";
[sender setTitle:str forState:(UIControlStateNormal)];
}
//完成
- (IBAction)done:(id)sender {
NSString *startTime = @"";
NSString *endTime = @"";
NSInteger dateType = (self.showType == MLDatePickerModeYM) ? 1 : 2;
if((self.showType == MLDatePickerModeYM)){
if (![self.monthTF.text notNilOrEmpty]) {
return;
}
startTime = endTime = self.monthTF.text;
self.block(dateType, startTime, endTime);
[self.navigationController popViewControllerAnimated:YES];
}else{
if ((![self.startDayTF.text notNilOrEmpty])||(![self.endDayTF.text notNilOrEmpty])) {
return;
}
NSDate *start = [NSDate br_getDate:self.startDayTF.text format:self.selectDateFormatter];
NSDate *end = [NSDate br_getDate:self.endDayTF.text format:self.selectDateFormatter];
BOOL minMoreThanMax = [start br_compare:end format:self.selectDateFormatter] == NSOrderedDescending;
if (minMoreThanMax) {
SVHUD_HINT(@"开始时间不得大于结束时间!");
}else{
startTime = self.startDayTF.text;
endTime = self.endDayTF.text;
self.block(dateType, startTime, endTime);
[self.navigationController popViewControllerAnimated:YES];
}
}
}
@end