全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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

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

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

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

[self.pickerView selectRow:xxx inComponent:xxx animated:YES];

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

复制代码 代码如下:
[self pickerView:self.pickerView didSelectRow:0 inComponent:0 ];//联动轮子1  必须得本轮有数据后触发否则crash

先看下效果图


关于设置默认值,三级联动,用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【要在获取数据成功后再执行这部操作,因此放在数据请求成功的回调内】,代码为

 [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

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


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

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

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

.h文件

#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文件

#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)导入

#import "ZLMAddressPickerView.h"

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

@property (strong, nonatomic) ZLMAddressPickerView *addressPickerView;

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

- (ZLMAddressPickerView *)addressPickerView {
  if (!_addressPickerView) {
    _addressPickerView     = [[ZLMAddressPickerView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT-244-64, SCREEN_WIDTH, 244)];
    _addressPickerView.delegate = self;
  }
  return _addressPickerView;
}

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

 [self.view addSubview:self.addressPickerView];

(5)别忘了实现代理

#pragma mark - ZLMAddressPickerViewDelegate

- (void)addressPickerViewDidSelected:(NSString *)areaName {

  self.areaLabel.text = areaName;//将传回的详细地址字符串赋值

  [self addressPickerViewDidClose];
}

- (void)addressPickerViewDidClose {

  [self.addressPickerView removeFromSuperview];
}

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


# iOS三级联动选择器  # ios  # 三级城市选择器  # iOS实现自定义起始时间选择器视图  # iOS自定义日期、时间、城市选择器实例代码  # Android自定义View仿IOS圆盘时间选择器  # iOS实现自定义日期选择器示例  # Android开发中实现IOS风格底部选择器(支持时间 日期 自定义)  # iOS开发之UIPickerView实现城市选择器的步骤详解  # iOS中使用UIDatePicker制作时间选择器的实例教程  # 本轮  # 默认值  # 要在  # 选择器  # 到第  # 先看  # 几个  # 放在  # 也会  # 是有  # 又是  # 就能  # 依此类推  # 才会  # 你在  # 当你  # 最喜欢  # 这部  # 要想  # 再去 


相关文章: 网站制作公司排行榜,抖音怎样做个人官方网站  重庆市网站制作公司,重庆招聘网站哪个好?  ,网站推广常用方法?  建站之星如何实现PC+手机+微信网站五合一建站?  如何在Windows虚拟主机上快速搭建网站?  一键制作网站软件下载安装,一键自动采集网页文档制作步骤?  如何打造高效商业网站?建站目的决定转化率  怀化网站制作公司,怀化新生儿上户网上办理流程?  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  小型网站制作HTML,*游戏网站怎么搭建?  早安海报制作网站推荐大全,企业早安海报怎么每天更换?  电脑免费海报制作网站推荐,招聘海报哪个网站多?  建站之星免费版是否永久可用?  ,在苏州找工作,上哪个网站比较好?  建站主机选哪家性价比最高?  建站之星如何通过成品分离优化网站效率?  广德云建站网站建设方案与建站流程优化指南  建站之星如何开启自定义404页面避免用户流失?  如何快速搭建高效香港服务器网站?  油猴 教程,油猴搜脚本为什么会网页无法显示?  建站之星2.7模板快速切换与批量管理功能操作指南  如何自定义建站之星网站的导航菜单样式?  Swift开发中switch语句值绑定模式  5种Android数据存储方式汇总  宁波免费建站如何选择可靠模板与平台?  设计网站制作公司有哪些,制作网页教程?  建站VPS配置与SEO优化指南:关键词排名提升策略  C++时间戳转换成日期时间的步骤和示例代码  PHP正则匹配日期和时间(时间戳转换)的实例代码  婚礼视频制作网站,学习*后期制作的网站有哪些?  北京建设网站制作公司,北京古代建筑博物馆预约官网?  网站视频怎么制作,哪个网站可以免费收看好莱坞经典大片?  如何在建站主机中优化服务器配置?  如何制作网站标识牌,动态网站如何制作(教程)?  焦点电影公司作品,电影焦点结局是什么?  如何快速生成可下载的建站源码工具?  C#怎么使用委托和事件 C# delegate与event编程方法  安徽网站建设与外贸建站服务专业定制方案  如何通过WDCP绑定主域名及创建子域名站点?  seo网站制作优化,网站SEO优化步骤有哪些?  如何在阿里云完成域名注册与建站?  建站之星如何快速更换网站模板?  建站主机助手选型指南:2025年热门推荐与高效部署技巧  如何快速重置建站主机并恢复默认配置?  专业网站制作企业网站,如何制作一个企业网站,建设网站的基本步骤有哪些?  潍坊网站制作公司有哪些,潍坊哪家招聘网站好?  如何在服务器上配置二级域名建站?  猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?  制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?  网站建设设计制作营销公司南阳,如何策划设计和建设网站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。