iOS自定义日期、时间、城市选择器实例代码

选择器,我想大家都不陌生,当需要用户去选择某些范围值内的一个固定值时,我们会采用选择器的方式。选择器可以直观的提示用户选择的值范围、统一信息的填写格式,同时也方便用户快速的进行选择,比如对于性别,正常情况下就只有男女两种情况,那这时候用一个选择器给用户进行选择的话,可以避免错误数据的输入,也更方便用户去填写。再比如需要获取用户的生日信息时,采用选择器的方式可以统一生日的格式,如果让用户自行输入的话,可能会出现各种各样的生日信息格式,不利于数据的存储,但是采用选择器的方式的话,用户可找到对应的日期进行选择即可。

在iOS有专门的一个选择器类UIPickerView,进入UIPickerView的头文件,我们可以发现 UIPickerView直接继承了UIView,其事件处理通过代理方法完成,所以创建UIPickerView的时候记得签它的代理UIPickerViewDataSourceUIPickerViewDelegate。其实它和UITbleView有点像,不过UIPickerView还多了个列属性,UITbleView我们都很熟了,所以可以对比UITbleView的相关属性和代理方法来学习记忆UIPickerView。

一. UIPickerView的代理方法

(1)UIPickerViewDataSource对应的代理方法有(其代理方法必须要实现):

返回显示的列数

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;

返回每一列中需要显示的行数

代码如下:

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;

(2)UIPickerViewDelegate对应的代理方法(其代理方法根据需求进行选择性实现):

返回每一列的宽度

代码如下:

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component;

返回每一列的高度

代码如下:

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component ;

返回UIPickerView控件中指定列的列表项的要显示的内容

代码如下:

- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component ;

返回UIView,作为该UIPickerView控件中指定列的指定行的显示视图

代码如下:

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view ;

选择指定列中的指定行

代码如下:

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component ;

二、UIPickerView和UIDatePicker。

UIDatePicker是系统帮我们封装好的一个时间日期选择器,继承于UIControl,UIDatePicker有一定的局限性,因为它只有四种显示样式:

UIDatePickerModeTime,
UIDatePickerModeDate,
UIDatePickerModeDateAndTime,
UIDatePickerModeCountDownTimer,

如果需求和这四种样式都不符合的话,那么就没办法使用UIDatePicker,比如当只需要显示年、月信息的时候,显然UIDatePicker没办法满足我们的需求,那这时我们只能通过UIPickerView来自定义自己想要的选择器。

三、UIPickerView的自定义使用

(1)创建基类继承于UIView的WXZBasePickView。

我们常见的选择器的样式是一个带透明背景色的view,底部是内容的选择器,有确定和取消按钮,大致如图:

所以我们创建一个基类view,这个view的样式如图所示样式,之后根据内容的差别创建基于该view的选择器。

在.h中声明各个属性及方法

#import <UIKit/UIKit.h>

@interface WXZBasePickView : UIView

@property (nonatomic, strong) UIView *contentView;

//选择器
@property (nonatomic, strong)UIPickerView *pickerView;
//取消按钮
@property (nonatomic, strong)UIButton *cancelButton;
 //确定按钮
@property (nonatomic, strong)UIButton *confirmButton;

//选择器每一列的高度
@property (nonatomic, assign)CGFloat pickerViewHeight;

/**
 * 创建视图,初始化视图时初始数据
 */
- (void)initPickView;

/**
 * 确认按钮的点击事件
 */
- (void)clickConfirmButton;

/**
 * pickerView的显示
 */
- (void)show;

/**
 * 移除pickerView
 */
- (void)disMiss;

@end

在.m中实现相关方法

#import "WXZBasePickView.h"
#define ScreenWidth [UIScreen mainScreen].bounds.size.width
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
@implementation WXZBasePickView

- (instancetype)init
{
  self = [super init];
  if (self) {

    _pickerViewHeight   = 250;
    self.bounds = [UIScreen mainScreen].bounds;
    self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.64];
    self.layer.opacity = 0.0;

    UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(disMiss)];
    self.userInteractionEnabled = YES;
    [self addGestureRecognizer:tap];

    [self addSubview:self.contentView];
    [self.contentView addSubview:self.pickerView];
    [self.contentView addSubview:self.cancelButton];
    [self.contentView addSubview:self.confirmButton];

    [self initPickView];
   }
  return self;
}
//初始化选择器内容,创建子类时需实现该父类方法
-(void)initPickView{

}
//点击确定按钮
- (void)clickConfirmButton
{
  [self disMiss];
}

//点击取消按钮
- (void) clickCancelButton
{
  [self disMiss];
}

//显示选择器
 - (void)show
{
  [[UIApplication sharedApplication].keyWindow addSubview:self];
  [self setCenter:[UIApplication sharedApplication].keyWindow.center];
  [[UIApplication sharedApplication].keyWindow bringSubviewToFront:self];

    CGRect frame = self.contentView.frame;
    frame.origin.y -= self.contentView.frame.size.height;
    [UIView animateWithDuration:0.4 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
      [self.layer setOpacity:1.0];
      self.contentView.frame = frame;

    } completion:^(BOOL finished) {
    }];

  }

//移除选择器
- (void)disMiss
{

    CGRect frame = self.contentView.frame;
    frame.origin.y += self.contentView.frame.size.height;
    [UIView animateWithDuration:0.4 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
      [self.layer setOpacity:0.0];
      self.contentView.frame = frame;
    } completion:^(BOOL finished) {
      [self removeFromSuperview];
    }];

}
//设置选择器的高度
- (void)setPickerViewHeight:(CGFloat)pickerViewHeight
{
  _pickerViewHeight = pickerViewHeight;
  self.contentView.frame = CGRectMake(self.contentView.frame.origin.x, self.contentView.frame.origin.y, self.contentView.frame.size.width, pickerViewHeight);
}

- (UIView *)contentView
{
  if (!_contentView) {

    _contentView = [[UIView alloc]initWithFrame:CGRectMake(0, ScreenHeight, ScreenWidth, self.pickerViewHeight)];
    [_contentView setBackgroundColor:[UIColor whiteColor]];
  }
  return _contentView;
}

- (UIPickerView *)pickerView
{
  if (!_pickerView) {

    _pickerView = [[UIPickerView alloc]initWithFrame:CGRectMake(0, 0, self.contentView.frame.size.width, self.contentView.frame.size.height)];
    [_pickerView setBackgroundColor:[UIColor whiteColor]];

  }
  return _pickerView;
}

- (UIButton *)cancelButton
{
  if (!_cancelButton) {

    _cancelButton = [[UIButton alloc]initWithFrame:CGRectMake(16, 0, 44, 44)];
    [_cancelButton setTitle:@"取消" forState:UIControlStateNormal];
    [_cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];

    [_cancelButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
    [_cancelButton addTarget:self action:@selector(clickCancelButton) forControlEvents:UIControlEventTouchUpInside];
  }
  return _cancelButton;
}

- (UIButton *)confirmButton
{
  if (!_confirmButton) {

    _confirmButton = [[UIButton alloc]initWithFrame:CGRectMake(self.contentView.frame.size.width - self.cancelButton.frame.size.width - self.cancelButton.frame.origin.x, self.cancelButton.frame.origin.y, self.cancelButton.frame.size.width, self.cancelButton.frame.size.height)];
    [_confirmButton setTitle:@"确定" forState:UIControlStateNormal];
    [_confirmButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];

    [_confirmButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
    [_confirmButton addTarget:self action:@selector(clickConfirmButton) forControlEvents:UIControlEventTouchUpInside];
  }
  return _confirmButton;
}

@end

(2)、自定义一个日期选择器,可选择显示年、月或者年、月、日以及是否显示“至今”选项。

创建继承于我们自定义好的WXZBasePickView的日期选择器WXZPickDateView

.h声明相关属性和方法

#import "WXZBasePickView.h"
@class WXZBasePickView;
//选择器的选择代理方法
@protocol PickerDateViewDelegate<NSObject>
- (void)pickerDateView:(WXZBasePickView *)pickerDateView selectYear:(NSInteger)year selectMonth:(NSInteger)month selectDay:(NSInteger)day;
@end

@interface WXZPickDateView : WXZBasePickView

@property(nonatomic, weak)id <PickerDateViewDelegate>delegate ;
@property(nonatomic, assign)BOOL isAddYetSelect;//是否增加至今的选项
@property(nonatomic, assign)BOOL isShowDay;//是否显示日
//设置默认显示的值
-(void)setDefaultTSelectYear:(NSInteger)defaultSelectYear defaultSelectMonth:(NSInteger)defaultSelectMonth defaultSelectDay:(NSInteger)defaultSelectDay;

@end

.m实现相关方法

#import "WXZPickDateView.h"
@interface WXZPickDateView()<UIPickerViewDataSource, UIPickerViewDelegate>
/** 选择的年 */
@property (nonatomic, assign)NSInteger selectYear;
/** 选择的月 */
@property (nonatomic, assign)NSInteger selectMonth;
/** 选择的日 */
@property (nonatomic, assign)NSInteger selectDay;
@property (nonatomic, assign)NSInteger currentYear;
@property (nonatomic, assign)NSInteger currentMonth;
@property (nonatomic, assign)NSInteger currentDay;
@property (nonatomic, assign)NSInteger defaultYear;
@property (nonatomic, assign)NSInteger defaultMonth;
@property (nonatomic, assign)NSInteger defaultDay;

@property (nonatomic, assign)NSInteger minShowYear;
@property (nonatomic, assign)NSInteger yearSum;
@end
@implementation WXZPickDateView

- (void)initPickView
{
  [super initPickView];
  _minShowYear = 1940;//最小年份
  NSCalendar *gregorian = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  // 获取当前日期
  NSDate* dt = [NSDate date];
  // 指定获取指定年、月、日、时、分、秒的信息
  unsigned unitFlags = NSCalendarUnitYear |
  NSCalendarUnitMonth | NSCalendarUnitDay |
  NSCalendarUnitHour | NSCalendarUnitMinute |
  NSCalendarUnitSecond | NSCalendarUnitWeekday;
  // 获取不同时间字段的信息
  NSDateComponents* comp = [gregorian components: unitFlags fromDate:dt];

  _yearSum = comp.year-_minShowYear+1;
  _currentYear=comp.year;
  _currentMonth=comp.month;
  _currentDay=comp.day;

  _selectYear = comp.year;
  _selectMonth = comp.month;
  _selectDay  = comp.day;

  _defaultYear = comp.year;
  _defaultMonth = comp.month;
  _defaultDay=comp.day;
  [self.pickerView setDelegate:self];
  [self.pickerView setDataSource:self];

}
-(void)setDefaultTSelectYear:(NSInteger)defaultSelectYear defaultSelectMonth:(NSInteger)defaultSelectMonth defaultSelectDay:(NSInteger)defaultSelectDay{

  if (defaultSelectYear!=0) {
   _defaultYear=defaultSelectYear;
  }

  if (defaultSelectMonth!=0) {
    _defaultMonth = defaultSelectMonth;
  }

  if (defaultSelectDay!=0) {
     _defaultDay=defaultSelectDay;
  }

  if (defaultSelectYear==-1) {
    _defaultYear=_currentYear+1;
    _defaultMonth=1;
    _defaultDay=1;
  }

  [self.pickerView selectRow:(_defaultYear - _minShowYear) inComponent:0 animated:NO];
  [self.pickerView reloadComponent:1];
  [self.pickerView selectRow:(_defaultMonth - 1) inComponent:1 animated:NO];
  if (_isShowDay==YES) {
    [self.pickerView reloadComponent:2];
    [self.pickerView selectRow:_defaultDay inComponent:1 animated:NO];
  }

  [self refreshPickViewData];

}
-(void)setIsAddYetSelect:(BOOL)isAddYetSelect{
  _isAddYetSelect = isAddYetSelect;
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
//判断是否要显示日,如果显示则返回3列,反之返回2列
  if (_isShowDay==YES) {
    return 3;
  }else{
    return 2;
  }
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
  if (component == 0) {
    if (_isAddYetSelect==YES) {
      //显示至今选项的话,需要比总共要显示的年份多返回一行
      return self.yearSum+1;

    }else{

      return self.yearSum;
    }
  }else if(component == 1) {
    NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
    if (yearSelected==_currentYear+1) {
      //至今选项的时候月份信息不返回
      return 0;
    }else{

      return 12;
    }
  }else {
    NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
    if (yearSelected==_currentYear+1) {
       //至今选项的时候日信息不返回
      return 0;
    }else{
    NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
    NSInteger monthSelected = [pickerView selectedRowInComponent:1] + 1;
    return [self getDaysWithYear:yearSelected month:monthSelected];
    }
  }

}
//根据年、月判断日期天数
- (NSInteger)getDaysWithYear:(NSInteger)year
            month:(NSInteger)month
{
  switch (month) {
    case 1:
      return 31;
      break;
    case 2:
      if (year%400==0 || (year%100!=0 && year%4 == 0)) {
        return 29;
      }else{
        return 28;
      }
      break;
    case 3:
      return 31;
      break;
    case 4:
      return 30;
      break;
    case 5:
      return 31;
      break;
    case 6:
      return 30;
      break;
    case 7:
      return 31;
      break;
    case 8:
      return 31;
      break;
    case 9:
      return 30;
      break;
    case 10:
      return 31;
      break;
    case 11:
      return 30;
      break;
    case 12:
      return 31;
      break;
    default:
      return 0;
      break;
  }
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
  //每一行的高度
  return 36;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{

  NSInteger selectYear;
  NSInteger selectMonth;

  switch (component) {
    case 0:

      [pickerView reloadComponent:1];
      if (_isAddYetSelect==YES) {
        selectYear = row+_minShowYear+1;
      }else{
        selectYear = row+_minShowYear;
      }
      if (_isShowDay==YES) {
        [pickerView reloadComponent:2];
      }
      break;
    case 1:
      selectMonth = row+1;
      if (_isShowDay==YES) {
        [pickerView reloadComponent:2];
      }
    default:
      break;
  }

  [self refreshPickViewData];

}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{

  NSString *text;
  if (component == 0) {

    if (_isAddYetSelect==YES) {

      if (row+_minShowYear==_currentYear+1) {
        text=@"至今";

      }else{

        text = [NSString stringWithFormat:@"%zd年", row + _minShowYear];

      }

    }else{

      text = [NSString stringWithFormat:@"%zd年", row + _minShowYear];
    }

  }else if (component == 1){
    if (_isAddYetSelect==YES) {
      NSInteger yearSelected = [pickerView selectedRowInComponent:0] + self.minShowYear;
      if (yearSelected==_currentYear+1) {
        text = [NSString stringWithFormat:@""];
      }else{
        text = [NSString stringWithFormat:@"%zd月", row + 1];
      }
    }else{
      text = [NSString stringWithFormat:@"%zd月", row + 1];
    }

  }else{
    text = [NSString stringWithFormat:@"%zd日", row + 1];
  }

  UILabel *label = [[UILabel alloc]init];
  label.textAlignment = 1;
  label.font = [UIFont systemFontOfSize:16];
  label.text = text;

  return label;
}

- (void)clickConfirmButton
{

  if ([self.delegate respondsToSelector:@selector(pickerDateView:selectYear:selectMonth:selectDay:)]) {

    [self.delegate pickerDateView:self selectYear:self.selectYear selectMonth:self.selectMonth selectDay:self.selectDay];

  }

  [super clickConfirmButton];

}

- (void)refreshPickViewData
{

  self.selectYear = [self.pickerView selectedRowInComponent:0] + self.minShowYear;

  self.selectMonth = [self.pickerView selectedRowInComponent:1] + 1;
  if (_isShowDay==YES) {
     self.selectDay  = [self.pickerView selectedRowInComponent:2] + 1;
  }

}

- (void)setYearLeast:(NSInteger)yearLeast
{
  _minShowYear = yearLeast;
}

- (void)setYearSum:(NSInteger)yearSum
{
  _yearSum = yearSum;
}

-(void)setIsShowDay:(BOOL)isShowDay{
  _isShowDay=isShowDay;
}

@end

(3) 创建继承于WXZBasePickView的时间选择器WXZPickTimeView。

.h声明属性及相关方法

#import "WXZBasePickView.h"
@class WXZPickTimeView;

@protocol PickTimeViewDelegate<NSObject>
- (void)pickerTimeView:(WXZPickTimeView *)pickerTimeView selectHour:(NSInteger)hour selectMinute:(NSInteger)minute ;

@end
@interface WXZPickTimeView : WXZBasePickView
@property(nonatomic, weak)id <PickTimeViewDelegate>delegate ;

-(void)setDefaultHour:(NSInteger)hour defaultMinute:(NSInteger)minute ;
@end

.m实现相关方法

#import "WXZPickTimeView.h"
@interface WXZPickTimeView () <UIPickerViewDataSource, UIPickerViewDelegate>{
  UIDatePicker  *_datePicker;
}

@property (nonatomic, assign)NSInteger selectHour;
@property (nonatomic, assign)NSInteger selectMinute;
@property (nonatomic, assign)NSInteger day;
@property (nonatomic, assign)NSInteger defaultHour;
@property (nonatomic, assign)NSInteger defaultMinute;

@end

@implementation WXZPickTimeView

 - (void)initPickView
{
  [super initPickView];

  NSCalendar *gregorian = [[NSCalendar alloc]
               initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  // 获取当前日期
  NSDate* dt = [NSDate date];
  // 定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
  unsigned unitFlags = NSCalendarUnitYear |
  NSCalendarUnitMonth | NSCalendarUnitDay |
  NSCalendarUnitHour | NSCalendarUnitMinute |
  NSCalendarUnitSecond | NSCalendarUnitWeekday;
  // 获取不同时间字段的信息
  NSDateComponents* comp = [gregorian components: unitFlags
                     fromDate:dt];

  _selectHour=comp.hour;
  _selectMinute=comp.minute;

  [self.pickerView setDelegate:self];
  [self.pickerView setDataSource:self];

  [self.pickerView selectRow:_selectHour inComponent:0 animated:NO];
  [self.pickerView selectRow:_selectMinute inComponent:1 animated:NO];

}
-(void)setDefaultHour:(NSInteger)hour defaultMinute:(NSInteger)minute{

  if (hour!=0) {

   _defaultHour=hour;

  }else{
    _defaultHour=_selectHour;

  }
  if (minute!=0) {

    _defaultMinute = minute;

  }else{

    _defaultMinute=_selectMinute;
  }
  [self.pickerView selectRow:_defaultHour inComponent:0 animated:NO];
  [self.pickerView reloadComponent:1];
  [self.pickerView selectRow:_defaultMinute inComponent:1 animated:NO];
  [self refreshPickTimeViewData];

}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
  return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
  if (component == 0) {
    return 24;
  }else {
    return 60;
  }
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
  return 36;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
  switch (component) {
    case 0:
      [pickerView reloadComponent:1];

      break;
    case 1:

    default:
      break;
  }

  [self refreshPickTimeViewData];
}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{

  NSString *text;
  if (component == 0) {
    if (row<10) {
      text = [NSString stringWithFormat:@"0%zd时", row];
    }else{
      text = [NSString stringWithFormat:@"%zd时", row];
    }
  }else if (component == 1){
    if (row<10) {
      text = [NSString stringWithFormat:@"0%zd分", row ];
    }else{
      text = [NSString stringWithFormat:@"%zd分", row ];
    }
  }else{

  }

  UILabel *label = [[UILabel alloc]init];
  label.textAlignment = 1;
  label.font = [UIFont systemFontOfSize:16];
  label.text = text;
  return label;
}

- (void)clickConfirmButton
{
  if ([self.delegate respondsToSelector:@selector(pickerTimeView:selectHour:selectMinute:)]) {

    [self.delegate pickerTimeView:self selectHour:self.selectHour selectMinute:self.selectMinute];

  }

  [super clickConfirmButton];
}

- (void)refreshPickTimeViewData
{
  self.selectHour = [self.pickerView selectedRowInComponent:0];
  self.selectMinute = [self.pickerView selectedRowInComponent:1];

}
@end

(4)创建继承于WXZBasePickView的城市选择器WXZPickCityView。

.h声明相关属性和方法

#import "WXZBasePickView.h"
@class WXZPickCityView;

@protocol PickerCityViewDelegate<NSObject>

- (void)pickerArea:(WXZPickCityView *)pickerArea selectProvince:(NSString *)province selectCity:(NSString *)city;

@end
@interface WXZPickCityView : WXZBasePickView
@property(nonatomic, weak)id <PickerCityViewDelegate>delegate ;

/**设置默认的省市*/

-(void)setDefaultCity:(NSString *)defaultCity DefaultProvience:(NSString *)defaultProvience;
@end

.m实现相关方法

#import "WXZPickCityView.h"
@interface WXZPickCityView()<UIPickerViewDataSource, UIPickerViewDelegate>

@property (nonatomic, strong, nullable)NSArray *areaDataSource;

@property (nonatomic, strong, nullable)NSMutableArray *provinceArray;

@property (nonatomic, strong, nullable)NSMutableArray *cityArray;

@property (nonatomic, strong, nullable)NSMutableArray *selectedArray;//当前选中的数组

@property (nonatomic, strong, nullable)NSString *selectProvince;

@property (nonatomic, strong, nullable)NSString *selectCity;

@end

@implementation WXZPickCityView

- (void)initPickView
{
  [super initPickView];
  for (NSDictionary *dic in self.areaDataSource) {
    [self.provinceArray addObject:dic[@"state"]];
  }

  NSMutableArray *citysArr = [NSMutableArray arrayWithArray:[self.areaDataSource firstObject][@"cities"]];

  for (NSDictionary *dic in citysArr) {
    [self.cityArray addObject:dic[@"city"]];
  }

  self.selectProvince = self.provinceArray[0];
  self.selectCity = self.cityArray[0];

  [self.pickerView setDelegate:self];
  [self.pickerView setDataSource:self];

}

//设置默认显示的省市
-(void)setDefaultCity:(NSString *)defaultCity DefaultProvience:(NSString *)defaultProvience{

  for (NSInteger i = 0; i<_provinceArray.count; i++) {

    if ([_provinceArray[i] isEqualToString:defaultProvience]) {

      [self.pickerView selectRow:i inComponent:0 animated:NO];
      self.selectedArray = self.areaDataSource[i][@"cities"];

      [self.cityArray removeAllObjects];
      [self.selectedArray enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [self.cityArray addObject:obj[@"city"]];
      }];
      for (NSInteger j= 0; j<_cityArray.count; j++) {

        if ([defaultCity isEqualToString:_cityArray[j]]) {

          [self.pickerView selectRow:i inComponent:0 animated:NO];
          [self.pickerView reloadComponent:1];
          [self.pickerView selectRow:j inComponent:1 animated:NO];
          [self refreshSelectAreaData];
        }
      }
    }

  }

}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
  return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
  if (component == 0) {
    return self.provinceArray.count;
  }else {
    return self.cityArray.count;
  }
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
  return 36;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
  if (component == 0) {
    self.selectedArray = self.areaDataSource[row][@"cities"];

    [self.cityArray removeAllObjects];
    [self.selectedArray enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) {
      [self.cityArray addObject:obj[@"city"]];
    }];

    [pickerView reloadComponent:1];
    [pickerView selectRow:0 inComponent:1 animated:YES];

  }else if (component == 1) {
    if (self.selectedArray.count == 0) {
      self.selectedArray = [self.areaDataSource firstObject][@"cities"];
    }

  }else{
  }

  [self refreshSelectAreaData];
}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{

  for(UIView *singleLine in pickerView.subviews)
  {
    if (singleLine.frame.size.height < 1)
    {
      singleLine.backgroundColor =[UIColor grayColor];
    }
  }
  NSString *text;
  if (component == 0) {
    text = self.provinceArray[row];
  }else if (component == 1){
    text = self.cityArray[row];
  }else{

  }

  UILabel *label = [[UILabel alloc]init];
  label.textAlignment = 1;
  label.font = [UIFont systemFontOfSize:16];
  label.text = text;

  return label;
}

- (void)clickConfirmButton
{

  [self.delegate pickerArea:self selectProvince:self.selectProvince selectCity:self.selectCity];

  [super clickConfirmButton];
}

- (void)refreshSelectAreaData
{
  NSInteger provienceIndex = [self.pickerView selectedRowInComponent:0];
  NSInteger cityIndex = [self.pickerView selectedRowInComponent:1];

  self.selectProvince = self.provinceArray[provienceIndex];
  self.selectCity = self.cityArray[cityIndex];

}

- (NSArray *)areaDataSource
{
  if (!_areaDataSource) {
    NSString *path = [[NSBundle bundleForClass:[WXZPickCityView class]] pathForResource:@"area" ofType:@"plist"];
    _areaDataSource = [[NSArray alloc]initWithContentsOfFile:path];
  }
  return _areaDataSource;
}

- (NSMutableArray *)provinceArray
{
  if (!_provinceArray) {
    _provinceArray = [NSMutableArray array];
  }
  return _provinceArray;
}

- (NSMutableArray *)cityArray
{
  if (!_cityArray) {
    _cityArray = [NSMutableArray array];
  }
  return _cityArray;
}

- (NSMutableArray *)selectedArray
{
  if (!_selectedArray) {
    _selectedArray = [NSMutableArray array];
  }
  return _selectedArray;
}

@end

(5)创建继承于WXZBasePickView的单列选择器WXZCustomPickView,可根据传进来的数组显示相关的选择内容

.h声明相关属性和方法

#import "WXZBasePickView.h"

@class WXZCustomPickView;

@protocol CustomPickViewDelegate<NSObject>
- (void)customPickView:(WXZCustomPickView *)customPickView selectedTitle:(NSString *)selectedTitle;
@end

@interface WXZCustomPickView :WXZBasePickView

@property (nonatomic, strong)NSMutableArray *dataArray;
@property(nonatomic, copy)NSString *defalutSelectRowStr;
@property(nonatomic, weak)id <CustomPickViewDelegate>delegate;
@end

.m实现相关方法

#import "WXZCustomPickView.h"
@interface WXZCustomPickView()<UIPickerViewDataSource, UIPickerViewDelegate>
/** 1.选中的字符串 */
@property (nonatomic, strong, nullable)NSString *selectedTitle;

@end

@implementation WXZCustomPickView

- (void)initPickView
{
  [super initPickView];

  _dataArray=[NSMutableArray mutableCopy];

  [self.pickerView setDelegate:self];
  [self.pickerView setDataSource:self];

}

-(void)setDefalutSelectRowStr:(NSString *)defalutSelectRowStr{
  _defalutSelectRowStr=defalutSelectRowStr;

  for (NSInteger i = 0; i<_dataArray.count; i++) {

    if ([_dataArray[i] isEqualToString:_defalutSelectRowStr]) {
      [self.pickerView reloadAllComponents];
      [self.pickerView selectRow:i inComponent:0 animated:NO];

    }
  }
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
  return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
  return self.dataArray.count;
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
  return 36;
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{

  return self.frame.size.width;

}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
  self.selectedTitle = self.dataArray[row];
}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{

  for(UIView *singleLine in pickerView.subviews)
  {
    if (singleLine.frame.size.height < 1)
    {
      singleLine.backgroundColor =[UIColor grayColor];
    }
  }

  UILabel *label = [[UILabel alloc]init];
  label.font=[UIFont systemFontOfSize:16];
  label.textAlignment = 1;

  label.text=self.dataArray[row];

    return label;

}
#pragma mark -点击确定按钮
- (void)clickConfirmButton
{
  [self.delegate customPickView:self selectedTitle:self.selectedTitle];

  [super clickConfirmButton];
}

- (void)setDataArray:(NSMutableArray *)dataArray
{
  _dataArray = dataArray;
  _selectedTitle = dataArray.firstObject;
  [self.pickerView reloadAllComponents];

}

@end

这样,几种类型的选择器我们都定义好了,在需要选择器的地方,根据需求创建相应的选择器即可。

四、如何使用已创建好的自定义选择器

引入自定义好的选择器,声明相关属性,签相关协议

#import "ViewController.h"
#import "WXZPickDateView.h"
#import "WXZPickAreaView.h"
#import "WXZPickTimeView.h"
#import "WXZCustomPickView.h"
@interface ViewController ()<PickerDateViewDelegate,PickerAreaViewDelegate,PickTimeViewDelegate,CustomPickViewDelegate>{
  UIButton *dateButton;
  UIButton *selectAreabutton;
  UIButton *selectTimeButton;
  UIButton *singlePickViewSelectButton;
  BOOL isShowDay;//是否显示日信息
}

@end

创建相应的按钮,触发相应的选择器

- (void)viewDidLoad {
  [super viewDidLoad];

  dateButton=[UIButton buttonWithType:UIButtonTypeCustom];
  dateButton.frame=CGRectMake(100, 100, 100, 50);
  [dateButton setTitle:@"选择日期" forState:UIControlStateNormal];
  [self.view addSubview:dateButton];
  [dateButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  [dateButton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
  dateButton.tag = 1000;

   selectAreabutton=[UIButton buttonWithType:UIButtonTypeCustom];
  selectAreabutton.frame=CGRectMake(100, 200, 100, 50);
  [selectAreabutton setTitle:@"选择地区" forState:UIControlStateNormal];
  [self.view addSubview:selectAreabutton];
  [selectAreabutton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  [selectAreabutton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
  selectAreabutton.tag = 1001;
  selectTimeButton=[UIButton buttonWithType:UIButtonTypeCustom];
  selectTimeButton.frame=CGRectMake(100, 300, 100, 50);
  [selectTimeButton setTitle:@"选择时间" forState:UIControlStateNormal];
  [self.view addSubview:selectTimeButton];
  [selectTimeButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  [selectTimeButton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
  selectTimeButton.tag = 1002;

  singlePickViewSelectButton=[UIButton buttonWithType:UIButtonTypeCustom];
  singlePickViewSelectButton.frame=CGRectMake(100, 400, 100, 50);
  [singlePickViewSelectButton setTitle:@"单个数据选择器" forState:UIControlStateNormal];
  [self.view addSubview:singlePickViewSelectButton];
  [singlePickViewSelectButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  [singlePickViewSelectButton addTarget:self action:@selector(pickViewSelect:) forControlEvents:UIControlEventTouchUpInside];
  singlePickViewSelectButton.tag = 1003;

}

按钮的点击事件:

-(void)pickViewSelect:(UIButton *)button{
  if (button.tag==1000) {

      WXZPickDateView *pickerDate = [[WXZPickDateView alloc]init];

      [pickerDate setIsAddYetSelect:YES];//是否显示至今选项
      [pickerDate setIsShowDay:YES];//是否显示日信息
      [pickerDate setDefaultTSelectYear:2007 defaultSelectMonth:4 defaultSelectDay:1];//设定默认显示的日期
      [pickerDate setValidTime:2010];

      [pickerDate setDelegate:self];

      [pickerDate show];
  }else if (button.tag==1001){
    WXZPickAreaView *pickerArea = [[WXZPickAreaView alloc]init];

    [pickerArea setDelegate:self];

    [pickerArea setDefaultCity:@"上海" DefaultProvience:@"上海"];

    [pickerArea show];
    [self.view endEditing:YES];
  }else if (button.tag==1002){
    WXZPickTimeView *pickerArea = [[WXZPickTimeView alloc]init];

    [pickerArea setDelegate:self];

    [pickerArea setDefaultHour:14 defaultMinute:20];

    [pickerArea show];
    [self.view endEditing:YES];
  }else{
    NSMutableArray *arrayData = [NSMutableArray arrayWithObjects:@"2k以下",@"2k-5k",@"5k-10k",@"10k-15k",@"15k-25k",@"25k-50k",@"50k以上", nil];

    WXZCustomPickView *pickerSingle = [[WXZCustomPickView alloc]init];

    [pickerSingle setDataArray:arrayData];
    [pickerSingle setDefalutSelectRowStr:arrayData[0]];

    [pickerSingle setDelegate:self];

    [pickerSingle show];
    [self.view endEditing:YES];

  }
}

选择器的代理方法

-(void)pickerDateView:(WXZBasePickView *)pickerDateView selectYear:(NSInteger)year selectMonth:(NSInteger)month selectDay:(NSInteger)day{
  NSLog(@"选择的日期是:%ld %ld %ld",year,month,day);
  if (isShowDay==YES) {
    [dateButton setTitle:[NSString stringWithFormat:@"%ld年 %ld月 %ld日",year,month,day] forState:UIControlStateNormal];
  }else{
    [dateButton setTitle:[NSString stringWithFormat:@"%ld年 %ld月",year,month] forState:UIControlStateNormal];
  }

}

-(void)pickerArea:(WXZPickAreaView *)pickerArea selectProvince:(NSString *)province selectCity:(NSString *)city{
  NSLog(@"省市的选择%@ %@",province,city);
  [selectAreabutton setTitle:[NSString stringWithFormat:@"%@%@",province,city] forState:UIControlStateNormal];
}

-(void)customPickView:(WXZCustomPickView *)customPickView selectedTitle:(NSString *)selectedTitle{
  NSLog(@"选择%@",selectedTitle);
  [singlePickViewSelectButton setTitle:selectedTitle forState:UIControlStateNormal];
}
-(void)pickerTimeView:(WXZPickTimeView *)pickerTimeView selectHour:(NSInteger)hour selectMinute:(NSInteger)minute{
  NSLog(@"选择的时间:%ld %ld",hour,minute);
  [selectTimeButton setTitle:[NSString stringWithFormat:@"%ld时 %ld分",hour,minute] forState:UIControlStateNormal];
}

最后,看看效果图:

有需要的可以下载demo看看

github地址:https://github.com/wxzwork/CustomPickView

demo地址:CustomPickView_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android开发中实现IOS风格底部选择器(支持时间 日期 自定义)

    本文Github代码链接 https://github.com/AndroidMsky/AndoirdIOSPicker 先上图吧: 这是笔者最近一个项目一直再用的一个选择器库,自己也在其中做了修改,并决定持续维护下去. 先看使用方法: 日期选择: private void showDateDialog(List<Integer> date) { DatePickerDialog.Builder builder = new DatePickerDialog.Builder(this); bui

  • iOS实现自定义日期选择器示例

    iOS自定义日期选择器,下面只是说明一下怎么用,具体实现请在最后下载代码看看: 效果如下: .h文件解析 选择日期选择器样式 typedef enum{ DateStyleShowYearMonthDayHourMinute = 0, DateStyleShowMonthDayHourMinute, DateStyleShowYearMonthDay, DateStyleShowMonthDay, DateStyleShowHourMinute }XHDateStyle; //日期选择器样式 @

  • iOS 获取公历、农历日期的年月日的实例代码

    介绍三种方法获取 Date (NSDate) 的年月日. 用 date 表示当前日期.测试日期为公历 2017 年 2 月 5 日,农历丁酉年,鸡年,正月初九. let date: Date = Date() NSDate *date = [NSDate date]; 获取公历年月日 用 Calendar (NSCalendar) 获取公历年月日 let calendar: Calendar = Calendar(identifier: .gregorian) print("Year:"

  • iOS自定义日期demo分享

    有个项目需求是做个在日期上选择的,就是这种: 网上看了几个日期的demo都太厚重了,移植起来太麻烦,然后打算自己写. 就先写个简化的demo看看,主要有几个关键点: 首先要根据当前日期获取这个月有几天 然后判断这个月份第一天是周几 再根据上面两个数据在合理的位置显示数据 还要记录下当前的日期方便切换月份 如果调接口的话其实根据后台给数据比对下对应的日期展示数据即可 其中有一个容易迷糊的是获取的星期天是第一天,下标是1 所以我们的数组是这样的 _weekdays = [NSArray arrayW

  • iOS获取某个日期后n个月的日期

    一.给一个时间,给一个数,正数是以后n个月,负数是前n个月: -(NSDate *)getPriousorLaterDateFromDate:(NSDate *)date withMonth:(NSInteger)month { NSDateComponents *comps = [[NSDateComponents alloc] init]; [comps setMonth:month]; NSCalendar *calender = [[NSCalendar alloc] initWithC

  • iOS计算上次日期距离现在多久的代码

    本文实例为大家分享了iOS上次日期距离现在多久的计算代码,供大家参考,具体内容如下 /** * 计算上次日期距离现在多久 * * @param lastTime 上次日期(需要和格式对应) * @param format1 上次日期格式 * @param currentTime 最近日期(需要和格式对应) * @param format2 最近日期格式 * * @return xx分钟前.xx小时前.xx天前 */ + (NSString *)timeIntervalFromLastTime:(

  • POI对Excel自定义日期格式的读取(实例代码)

    用POI读取Excel数据:(版本号:POI3.7) 1.读取Excel private List<String[]> rosolveFile(InputStream is, String suffix, int startRow) throws IOException, FileNotFoundException { Workbook xssfWorkbook = null; if ("xls".equals(suffix)) { xssfWorkbook = new H

  • Android自定义指示器时间轴效果实例代码详解

    指示器时间轴在外卖.购物类的APP里会经常用到,效果大概就像下面这样,看了网上很多文章,大都是自己绘制,太麻烦,其实通过ListView就可以实现. 在Activity关联的布局文件activity_main.xml中放置一个ListView,代码如下.由于这个列表只是用于展示信息,并不需要用户去点击,所以将其clickable属性置为false:为了消除ListView点击产生的波纹效果,我们设置其listSelector属性的值为透明:我们不需要列表项之间的分割线,所以设置其divider属

  • vue实现自定义日期组件功能的实例代码

    实现一个日期组件,如图: components.js代码如下: Vue.component('sc-calendar',{ template:'<div class="scCalendar">' + '<div class="calendar_header">' + '<div class="prev" @click="prevMonth"> < </div>' + '&l

  • iOS自定义日期、时间、城市选择器实例代码

    选择器,我想大家都不陌生,当需要用户去选择某些范围值内的一个固定值时,我们会采用选择器的方式.选择器可以直观的提示用户选择的值范围.统一信息的填写格式,同时也方便用户快速的进行选择,比如对于性别,正常情况下就只有男女两种情况,那这时候用一个选择器给用户进行选择的话,可以避免错误数据的输入,也更方便用户去填写.再比如需要获取用户的生日信息时,采用选择器的方式可以统一生日的格式,如果让用户自行输入的话,可能会出现各种各样的生日信息格式,不利于数据的存储,但是采用选择器的方式的话,用户可找到对应的日期

  • IOS 自定义UIPickView详解及实例代码

    IOS 自定义UIPickView 苹果一直推崇使用原生的组件,自带的UIPickView其实也很漂亮了,看起来也很美观.但是有时候,产品会有一些特殊的设计和需求.本文将会讲解如何修改苹果原生的组件的属性,达到自定义UIPickView的效果. 需求如下.需要自定义一个Tab.自定义选中文字的颜色.自定义选中颜色背景,自定义未选中文字颜色. 修改未选中的文字的字体和颜色 经过分析,上面的取消和确定按钮实现起来还是很简单的.加一个条就好了,我就不介绍具体步骤,下面的没有选中时候文字的样色,已经字体

  • Android 日期选择器实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: //出生年月设置 private void birthSetting() { Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DAY_OF_YEAR, 1); new DatePickerDialog(mContext, new DatePickerDialog.OnDateSetListener() { @Override public void onDat

  • 微信小程序日期选择器实例代码

    /* JS代码部分 */ 3 const date = new Date() const years = [] const months = [] const days = [] const hours = [] const minutes = [] var thisMon = date.getMonth(); var thisDay = date.getDate(); for (let i = 2017; i <= date.getFullYear() + 1; i++) { years.pu

  • Java编程实现计算两个日期的月份差实例代码

    本文实例主要实现计算两个日期的月份差,具体如下: package com.forezp.util; import org.joda.time.DateTime; import org.joda.time.Months; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; /** * 在JAVA中,如何计算两个日期的月份差?<br> * * * @author Adm

  • Android自定义水波纹动画Layout实例代码

    话不多说,我们先来看看效果: Hi前辈搜索预览 这一张是<Hi前辈>的搜索预览图,你可以在这里下载这个APP查看更多效果: http://www.wandoujia.com/apps/com.superlity.hiqianbei LSearchView 这是一个MD风格的搜索框,集成了ripple动画以及search时的loading,使用很简单,如果你也需要这样的搜索控件不妨来试试:https://github.com/onlynight/LSearchView RippleEverywh

  • 微信小程序自定义音乐进度条的实例代码

    需求:显示音乐播放按钮.可手动拖拽进度条:页面中含多个音乐,播放当前音乐时暂停其他音乐播放. 小程序自带标签 audio 小程序自带的audio标签含固定的样式,且有最小尺寸.目前项目也不含name和author字段,所以放弃audio标签. 实现效果图 初始化音乐数据 <text>{{currentProcess}}</text> <slider bindchange="" bindtouchstart="" bindtouchend

随机推荐