服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS三级联动选择器的实现代码示例

iOS三级联动选择器的实现代码示例

2021-03-27 17:05APP叫我取个帅气的昵称 IOS

本篇文章主要介绍了iOS三级联动选择器的实现代码示例,这里整理了详细的代码,有需要的小伙伴可以参考下

无聊ing...封装个省市区三级联动选择器的小demo吧。

上家公司的三级地区选择器的数据是一次性通过网络请求就能获取到的,但新东家这边并不是,而是先选择了省获取省的id再去获取市,再通过得到市的id获取区域,show code之前,先看下需要考虑的几个点:

1)怎么设置默认值,关键代码

?
1
[self.pickerview selectrow:xxx incomponent:xxx animated:yes];

2)怎么让三级之间联动 ,关键代码

 

复制代码 代码如下:

[self pickerview:self.pickerview didselectrow:0 incomponent:0 ];//联动轮子1  必须得本轮有数据后触发否则crash

 

 

先看下效果图

iOS三级联动选择器的实现代码示例

关于设置默认值,三级联动,用uipickview的话就是有3个轮子(component),首先我们要想到,第一次向后台发起请求,我们只能获取到第0个component的数据,只有当你滚动轮子的时候才会获取到省的id发起请求来获得该省的市的数据,也就是第1个component的数据,依此类推,滚动第1个component发起请求来获取第2个component的数据,因此,pickview的监听轮子滚动的代理起了重要作用

 

复制代码 代码如下:

- (void)pickerview:(uipickerview *)pickerview didselectrow:(nsinteger)row incomponent:(nsinteger)component;

 

 

我们通过接口获取第0个component的数据,这边是后台规定的使用id=0,获取到以后,默认选中第0个component的第0个row并主动调用触发pick的轮子滚动代理来联动第1个component【要在获取数据成功后再执行这部操作,因此放在数据请求成功的回调内】,代码为

?
1
[self pickerview:self.pickerview didselectrow:0 incomponent:0 ];

在各轮子滚动过程中,用一个中间值

_selectedrow0记录下第0个component的选中行

_selectedrow1记录下第1个component的选中行

_selectedrow2记录下第2个component的选中行,

这里需要记住,滚动某个轮子只能对它后面的轮子产生影响,所以当滚动第0个component的时候使_selectedrow1,_selectedrow2均置为0,这里注意,上面提到的

默认选中第0个component的第0个row并主动调用触发pick的轮子滚动代理来联动第1个component

要先将轮子上的数据渲染好,设置好默认值才能主动调用监听轮子滚动的代理,否则会导致崩溃,另一个防崩溃的点如下图

iOS三级联动选择器的实现代码示例

发现第三级没数据的时候,如果你在代码里没加【安全措施】,那也会导致崩溃,要在请求到第三级的数据后做下判断,如果个数为空,将该级对应的数据源置为nil。(其它两级的轮子最好也加判断)

最后,由于这是个封装的类,最终要得到选中的详细信息,可通过代理或block传值给controller。

又是你们最喜欢show code环节:

.h文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import <uikit/uikit.h>
 
//定制代理协议
@protocol zlmaddresspickerviewdelegate <nsobject>
 
- (void)addresspickerviewdidselected:(nsstring *)areaname;//点击上方完成按钮的代理传回拼接好的选中地址
 
- (void)addresspickerviewdidclose;//点击关闭代理
 
@end
 
@interface zlmaddresspickerview : uiview
 
@property (weak, nonatomic) id<zlmaddresspickerviewdelegate> 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
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
#import "zlmaddresspickerview.h"
#import "afhttputils.h"
#import "areamodel.h"
@interface zlmaddresspickerview () <uipickerviewdatasource, uipickerviewdelegate>
@property (strong, nonatomic) uipickerview *pickerview;
@property (strong, nonatomic) areamodel  *provbridge;
@property (strong, nonatomic) areamodel  *citybridge;
@property (strong, nonatomic) areamodel  *areabridge;
@property (copy, nonatomic) nsarray<area *> * provdataarr;//省数组
@property (copy, nonatomic) nsarray<area *> * citydataarr;//市数组
@property (copy, nonatomic) nsarray<area *> * areadataarr;//区数组
@end
 
@implementation zlmaddresspickerview
{
  nsinteger _selectrow0;//记录第0个轮子的选择行
  nsinteger _selectrow1;
  nsinteger _selectrow2;
  nsstring *_areastring;//最后要传回的详细地址拼接字符串
  area *_promodel;//记录下选中省的数据
  area *_citymodel;
  area *_areamodel;
 
}
 
- (instancetype)initwithframe:(cgrect)frame
{
  self = [super initwithframe:frame];
  if (self) {
    [self setup];
  }
  return self;
}
 
- (void)setup {
 
  _selectrow0 = 0;
  _selectrow1 = 0;
  _selectrow2 = 0;
 
  self.backgroundcolor  = [uicolor whitecolor];
  uitoolbar *toolbar   = [[uitoolbar alloc] initwithframe:cgrectmake(0, 0, cgrectgetwidth(self.bounds), 44)];
  toolbar.backgroundcolor = [uicolor whitecolor];
  [self addsubview:toolbar];
  
  uibarbuttonitem *closeitem   = [[uibarbuttonitem alloc] initwithtitle:@"关闭" style:uibarbuttonitemstyleplain target:self action:@selector(selectaddressclose)];
  uibarbuttonitem *completeitem  = [[uibarbuttonitem alloc] initwithtitle:@"完成" style:uibarbuttonitemstyleplain target:self action:@selector(selectaddresscomplete)];
  uibarbuttonitem *spaceitem   = [[uibarbuttonitem alloc] initwithbarbuttonsystemitem:uibarbuttonsystemitemflexiblespace target:nil action:nil];
  toolbar.items                     = @[closeitem, spaceitem, completeitem];
  
  self.pickerview.frame = cgrectmake(0, 44, cgrectgetwidth(self.bounds), cgrectgetheight(self.bounds) - 44);
 
  [self addsubview:self.pickerview];
  
  [self downloadprov];
  
}
 
#pragma mark - http methods
 
/*省*/
- (void)downloadprov {
  
  nsmutabledictionary *dic = [nsmutabledictionary dictionarywithdictionary: @{@"id":@(0)} ];
  
  [afhttputils sendposttaskwithurl:[nsstring stringwithformat:@"%@/app/member/area",base_domain_url] paramenters:dic successhandle:^(nsurlsessiondatatask *task, id responseobject) {
    
     nslog(@"prov:%@",responseobject);
    
    self.provbridge = [areamodel mj_objectwithkeyvalues:responseobject];
    
    if (self.provbridge.error_code==0) {
      
      self.provdataarr=self.provbridge.data;
      
       [self pickerview:self.pickerview didselectrow:0 incomponent:0 ];//联动轮子1 必须得本轮有数据后才能触发didselect
      
      [self.pickerview reloadallcomponents];
  
    }
  } errorhandle:^(nserror *error) {
    
  }];
 
}
/*市*/
- (void)downloadcitywithid:(nsinteger)provid {
  
  nsmutabledictionary *dic = [nsmutabledictionary dictionarywithdictionary: @{@"id":@(provid)} ];
  
  [afhttputils sendposttaskwithurl:[nsstring stringwithformat:@"%@/app/member/area",base_domain_url] paramenters:dic successhandle:^(nsurlsessiondatatask *task, id responseobject) {
    
    nslog(@"city:%@",responseobject);
    
    self.citybridge = [areamodel mj_objectwithkeyvalues:responseobject];
  
    if (self.citybridge.error_code==0) {
      
      self.citydataarr=self.citybridge.data;
      
      [self.pickerview reloadcomponent:1];
      
      [self.pickerview selectrow:0 incomponent:1 animated:yes];//默认选择row0
      
      [self pickerview:self.pickerview didselectrow:0 incomponent:1 ];//联动轮子2 必须得本轮有数据后才能触发didselect
      
      _citymodel = self.citydataarr[_selectrow1];
      
      [self downloadareawithid:_citymodel.area_id];
      
    }
  } errorhandle:^(nserror *error) {
    
  }];
  
}
/*区*/
- (void)downloadareawithid:(nsinteger)cityid {
  
  nsmutabledictionary *dic = [nsmutabledictionary dictionarywithdictionary: @{@"id":@(cityid)} ];
  
  [afhttputils sendposttaskwithurl:[nsstring stringwithformat:@"%@/app/member/area",base_domain_url] paramenters:dic successhandle:^(nsurlsessiondatatask *task, id responseobject) {
    
    nslog(@"area:%@",responseobject);
    
    self.areabridge = [areamodel mj_objectwithkeyvalues:responseobject];
    
    if (self.areabridge.error_code==0&&self.areabridge.data.count>0) {
      
      self.areadataarr=self.areabridge.data;
      
    }else{
      
      self.areadataarr=nil;
      
    }
    [self.pickerview reloadcomponent:2];
    
    [self.pickerview selectrow:0 incomponent:2 animated:yes];
    
    [self pickerview:self.pickerview didselectrow:0 incomponent:2 ];
  
  } errorhandle:^(nserror *error) {
    
  }];
  
}
#pragma mark - events response
- (void)selectaddresscomplete {
  [self.delegate addresspickerviewdidselected:_areastring];
}
 
- (void)selectaddressclose {
  [self.delegate addresspickerviewdidclose];
}
 
#pragma mark - uipickerviewdatasource
 
//确定picker的轮子个数
- (nsinteger)numberofcomponentsinpickerview:(uipickerview *)pickerview {
  
  return 3;
}
 
//确定picker的每个轮子的item数
- (nsinteger)pickerview:(uipickerview *)pickerview numberofrowsincomponent:(nsinteger)component {
  if (component==0) {
     return self.provdataarr.count;
    
  }else if(component==1){
    return self.citydataarr.count;
    
  }else{
    return self.areadataarr.count;
    
  }
}
- (cgfloat)pickerview:(uipickerview *)pickerview rowheightforcomponent:(nsinteger)component{
  return 36;
}
 
//确定每个轮子的每一项显示什么内容
- (nsattributedstring *)pickerview:(uipickerview *)pickerview attributedtitleforrow:(nsinteger)row forcomponent:(nsinteger)component{
  
  nsdictionary * attrdic = @{nsforegroundcolorattributename:[uicolor blackcolor],
                nsfontattributename:[uifont systemfontofsize:12]};
  area *area;
  if (component==0) {
    area = self.provdataarr[row];
    
  }else if(component==1){
    area = self.citydataarr[row];
    
  }else{
    area = self.areadataarr[row];
   
  }
   nsattributedstring * attrstring = [[nsattributedstring alloc] initwithstring:area.name
                         attributes:attrdic];
  return attrstring;
}
 
//监听轮子的移动
- (void)pickerview:(uipickerview *)pickerview didselectrow:(nsinteger)row incomponent:(nsinteger)component {
  
  if (component==0) {
    
    _selectrow0 = [pickerview selectedrowincomponent:0];
    
    _selectrow1 = 0;
    
    _selectrow2 = 0;
    
    _promodel  = self.provdataarr[_selectrow0];
    
    [self downloadcitywithid:_promodel.area_id];
      
  }else if(component==1){
    
    _selectrow1 = [pickerview  selectedrowincomponent:1];
    
    _selectrow2 = 0;
    
    _citymodel = self.citydataarr[_selectrow1];
    
     [self downloadareawithid:_citymodel.area_id];
    
  }else{
    
    _selectrow2 = [pickerview selectedrowincomponent:2];
 
    if (self.areadataarr&&self.areadataarr.count>0) {
 
       _areamodel = self.areadataarr[_selectrow2];
    }else{
      _areamodel = nil;
    }
  }
   if(_areamodel==nil){
    _areastring = [nsstring stringwithformat:@"%@ %@",_promodel.name,_citymodel.name];
   }else{
   _areastring = [nsstring stringwithformat:@"%@ %@ %@",_promodel.name,_citymodel.name,_areamodel.name];
   }
}
 
#pragma mark - getters and setters
- (uipickerview *)pickerview {
  if (_pickerview == nil) {
    _pickerview = [[uipickerview alloc] init];
    _pickerview.delegate  = self;
    _pickerview.datasource = self;
    
  }
  return _pickerview;
}
 
@end

最后在controller中调用

(1)导入

?
1
#import "zlmaddresspickerview.h"

(2)定义一个对象并遵守代理协议

?
1
@property (strong, nonatomic) zlmaddresspickerview *addresspickerview;

(3)懒加载生成对象(个人习惯)

?
1
2
3
4
5
6
7
- (zlmaddresspickerview *)addresspickerview {
  if (!_addresspickerview) {
    _addresspickerview     = [[zlmaddresspickerview alloc] initwithframe:cgrectmake(0, screen_height-244-64, screen_width, 244)];
    _addresspickerview.delegate = self;
  }
  return _addresspickerview;
}

(4)在点击跳出三级联动选择器的地方

?
1
[self.view addsubview:self.addresspickerview];

(5)别忘了实现代理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma mark - zlmaddresspickerviewdelegate
 
- (void)addresspickerviewdidselected:(nsstring *)areaname {
 
  self.arealabel.text = areaname;//将传回的详细地址字符串赋值
 
  [self addresspickerviewdidclose];
}
 
- (void)addresspickerviewdidclose {
 
  [self.addresspickerview removefromsuperview];
}

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

原文链接:http://www.jianshu.com/p/2fbbe610ca2f

延伸 · 阅读

精彩推荐
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28