思路:
1.使用UIPickerView控件,设置3列,第1列显示省列表,第2列显示市列表,第3列显示区列表,并根据省市区条数控制当前列显示行数;
2.网上下载全国地址json文件,拖到工程中,并解析成对象列表备用;
3.在pickerView-titleForRow方法中根据当前列取出省或市或区,返回,设置显示内容;
4.在滚动时临时保存省市区三个position值,当省与市列表滚动时,刷新3个列表,在pickerView-titleForRow方法中重新取值显示。
一、下载省市区地址库json文件,拖动到工程中,并创建相应的省、市实体类,用于json解析后存放数据:
1.省实体类Province.h代码下如:
//省
#import <Foundation/Foundation.h>
#import "City.h"
@interface Province : NSObject
@property(nonatomic, strong) NSString *name;
@property(nonatomic, strong) NSMutableArray *city;
@end
2.省实体类Province.m代码如下:
//省
#import "Province.h"
@implementation Province
@end
3.市实体类City.h代码如下:
//市
#import <Foundation/Foundation.h>
@interface City : NSObject
@property(nonatomic, strong) NSString *name;
@property(nonatomic, strong) NSMutableArray *area;
@end
4.市实体类City.m代码如下:
//市
#import "City.h"
@implementation City
@end
二、解析省市区地址库json文件,存储到NSMutableArray集合中:
1.在ViewController.h中导入实体类.h头文件,代码如下:
//实现省市区城市选择
#import <UIKit/UIKit.h>
#import "Province.h"
#import "City.h"
@interface ViewController : UIViewController
@end
2.定义NSMutableArray集合用于存储省市区列表,懒加载读取工程中的json地址文件并解析存入NSMutableArray:
@interface ViewController ()
//用于存储解析后的地址列表
@property (nonatomic, strong) NSMutableArray *adressList;
//省略其他代码...
@end
@implementation ViewController
/*
懒加载,读取json文件的地址并存到列表中
*/
- (NSMutableArray *)adressList{
if(_adressList == nil){
//获取json文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"adress" ofType:@"json"];
//将json文件转为NSData
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
//解析json为NSMutableArray
_adressList = [self parseJson:data];
}
return _adressList;
}
/*
解析地址json
*/
- (NSMutableArray *)parseJson:(NSData *)data{
//解析列表json数据,NSArray中每个item为NSDictionary
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
//创建列表,用于实体类存放
NSMutableArray *provinceList = [NSMutableArray array];
/*
解析省列表,并存入provinceList
*/
for (NSDictionary *rootMap in array) {
Province *province = [[Province alloc] init];
//KVC:将NSDictionary解析成实际数据对象(Province为自定义实体类),两者的key名与类型必须一样
[province setValuesForKeysWithDictionary:rootMap];
/*
解析市列表,并存入cityList
*/
NSMutableArray *cityList = [NSMutableArray array];
for (NSDictionary *cityMap in province.city) {
City *city = [[City alloc] init];
//KVC:将NSDictionary解析成实际数据对象(City为自定义实体类),两者的key名与类型必须一样
[city setValuesForKeysWithDictionary:cityMap];
/*
解析区列表,并存入countyList
*/
NSMutableArray *countyList = [NSMutableArray array];
for (NSString *countyStr in city.area) {
[countyList addObject:countyStr];
}
//将区列表存储到对应市对象中
city.area = countyList;
[cityList addObject:city];
}
//将市列表存储到对应省对象中
province.city = cityList;
//将省对象存入列表
[provinceList addObject:province];
};
return provinceList;
}
三、创建UIPickerView控件,将省市区数据显示到UIPickerView中:
1.将UIPickerView控件拖动到Main.storyboard中,右击此控件,按住dataSource后面的"+",拖线到ViewController上,同理,右击此控件,将delegate也拖线到ViewController上,然后再按住此控件,拖线到代码上,创建成员引用变量,代码如下:
#import "ViewController.h"
//实现UIPickerView的数据源和代理
@interface ViewController () <UIPickerViewDelegate, UIPickerViewDataSource>
//省略其他代码...
//UIPickerView控件引用
@property (weak, nonatomic) IBOutlet UIPickerView *pickerV;
@end
2.实现numberOfComponentsInPickerView方法,返回固定3列:
/*
UIPickerView方法:返回列数
*/
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 3;
}
3.实现pickerView-numberOfRowsInComponent方法,设置每列显示行数,这里判断当前处于第0-2列,分别取出省市区对应的列表个数,返回显示行数:
/*
UIPickerView方法:返回行数,component表示第几列,从0开始
*/
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
if(component == 0){//省列表,返回个数
return self.adressList.count;
} else if(component == 1){//市列表,从当前选中的省中取出市列表,返回个数
Province *province = self.adressList[self.provincePosition];
if(province.city == nil || province.city.count == 0){
return 0;
}
return province.city.count;
} else if(component == 2){//县或区列表,从当前选中的市中取出区列表,返回个数
Province *province = self.adressList[self.provincePosition];
if(province.city == nil || province.city.count == 0){
return 0;
}
City *city = province.city[self.cityPosition];
if(city.area == nil || city.area.count == 0){
return 0;
}
return city.area.count;
}
return 0;
}
4.实现pickerView-titleForRow方法,显示当前行内容,这里根据row值从列表中分别取出省市区的字符串,并返回:
/*
UIPickerView方法:返回每行显示文本内容,与viewForRow二选一
*/
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
if(component == 0){//省列表,根据当前行row值,取出名称返回
Province *province = self.adressList[row];
return province.name;
} else if(component == 1){//市列表,根据当前行row值,取出名称返回
Province *province = self.adressList[self.provincePosition];
City *city = province.city[row];
return city.name;
} else if(component == 2){//县或区列表,根据当前行row值,取出名称返回
Province *province = self.adressList[self.provincePosition];
City *city = province.city[self.cityPosition];
return city.area[row];
}
return @"未知内容";
}
5.实现pickerView-didSelectRow方法,当每一列滚动时,记录当前position值,省市列滚动后,实时刷新所有列,更新市区列表数据:
//省略其他代码...;
//存入当前省选择position
@property (nonatomic, assign) NSInteger provincePosition;
//存入当前市选择position
@property (nonatomic, assign) NSInteger cityPosition;
//存入当前区选择position
@property (nonatomic, assign) NSInteger countyPosition;
//省略其他代码...;
/*
UIPickerView方法:选中时触发,component为列位置,row为行位置,从0开始
*/
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
NSLog(@"列position为: %d, 行position为: %d", (int)component, (int)row);
/*
当列表选中改变时,刷新所有列表,重新显示省市区
*/
if(component == 0){//省列表,取出row赋值
self.provincePosition = row;
} else if(component == 1){//市列表,取出row赋值
self.cityPosition = row;
} else if(component == 2){//县或区列表,取出row赋值
self.countyPosition = row;
return;
}
//刷新所有列表
[self.pickerV reloadAllComponents];
}
6.其他一些方法说明:
/*
UIPickerView方法:返回每行显示的View,与titleForRow二选一
*/
//- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
// //将缓存中的item的View拿出来使用
// UIView *v = view;
// if(v == nil){//当缓存中item的View为空时,则创建新的
// v = [[UIView alloc] init];
// }
// return v;
//}
/*
UIPickerView方法:返回指定列每行行高,一般和viewForRow配合使用
*/
//- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
// return 30;
//}
- (void)viewDidLoad {
[super viewDidLoad];
[self adressList];
//选中某一列某一行
// [self.pickerV selectRow:0 inComponent:0 animated:YES];
//获取当前列选中的行号,参数为列号
// NSInteger pos = [self.pickerV selectedRowInComponent:0];
//刷新所有列表
// [self.pickerV reloadAllComponents];
//刷新指定列表
// [self.pickerV reloadComponent:1];
}