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

时间:2022-12-07 21:02:52

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

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

一. uipickerview的代理方法

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

返回显示的列数

?
1
- (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有一定的局限性,因为它只有四种显示样式:

?
1
2
3
4
uidatepickermodetime,    
uidatepickermodedate,    
uidatepickermodedateandtime,
uidatepickermodecountdowntimer,

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

三、uipickerview的自定义使用

(1)创建基类继承于uiview的wxzbasepickview。

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#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中实现相关方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#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声明相关属性和方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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实现相关方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#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声明属性及相关方法

?
1
2
3
4
5
6
7
8
9
10
11
12
#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实现相关方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#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声明相关属性和方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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实现相关方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#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声明相关属性和方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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实现相关方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- (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;
 
}

按钮的点击事件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
-(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];
 
  }
}

选择器的代理方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-(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];
}

最后,看看效果图:

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

有需要的可以下载demo看看

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

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

原文链接:http://www.jianshu.com/p/c7fb8d7dba6d?utm_source=tuicool&utm_medium=referral#