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

时间:2021-05-02

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

在ios有专门的一个选择器类uipickerview,进入uipickerview的头文件,我们可以发现 uipickerview直接继承了uiview,其事件处理通过代理方法完成,所以创建uipickerview的时候记得签它的代理uipickerviewdatasource和uipickerviewdelegate。其实它和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,底部是内容的选择器,有确定和取消按钮,大致如图:

所以我们创建一个基类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

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章