iOS:UIPickerView实现三级城市联动

本文介绍如何利用UIPickerView控件在iOS应用中实现三级城市(省-市-区)联动效果。通过下载全国地址JSON文件,解析成对象列表,设置pickerView的代理方法来动态更新显示内容,并在滚动时更新对应列的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:

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];
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值