iOS小技能:地址选择器(支持省份,省市,省市区,支持显示上一次选择的地址)

208 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情

前言

采用UIPickerView实现,核心方法czh_getData:构建数据模型,先从网络进行获取数据,如果获取失败,直接取本地的city.json

  • 选择省市区效果

  • 选择省市

使用方法:

回调参数包括选中的省(provinceId)、市ID(cityId)区ID(areaid)

        [AddressPickerView areaPickerViewWithProvince:self.viewModel.AddressPickerModel.province city:self.viewModel.AddressPickerModel.city  provinceId:self.viewModel.AddressPickerModel.provinceId cityId:self.viewModel.AddressPickerModel.cityId cityBlock:^(NSString *province, NSString *city , NSString* provinceId,NSString* cityId) {
            weakSelf.viewModel.AddressPickerModel.province = province;
            weakSelf.viewModel.AddressPickerModel.city = city;
            weakSelf.viewModel.AddressPickerModel.provinceId = provinceId;
            weakSelf.viewModel.AddressPickerModel.cityId = cityId;
            NSString* Title =         [NSString stringWithFormat:@"%@%@",province,city] ;
            weakSelf.viewModel.ProductplaceModel.content = Title ;
            [self.viewModel.reloadProductPlaceModelSubject sendNext:nil];
            NSLog(@"更新信息   provinceId:%@ cityId:%@",provinceId,cityId);
        } showType:CZHAddressPickerViewTypeCity];

I 、核心代码

1.1 AddressPickerView的构建数据模型

从网络进行获取数据,如果获取失败,直接取本地的city.json

- (void)czh_getData {
    
    NSArray *tmp = [QCTAreaListTool getAreaList];

    if (tmp.count >0) {// 修改为不取本地的,数据量太大了
        self.dataSource = tmp;
    }else{//获取本地数据
        
        NSString *path = [[NSBundle mainBundle] pathForResource:@"city.json" ofType:nil];
        
        
        
        NSArray *array = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:path] options:NSJSONReadingMutableLeaves error:nil];
        
        self.dataSource = array;
        

        
        
    }
    
    
    NSMutableArray * tempArray = [NSMutableArray array];
    NSMutableArray * tempIDArray = [NSMutableArray array];

    for (NSDictionary * tempDic in self.dataSource) {
        [tempArray addObject:tempDic[areaName]];
        [tempIDArray addObject:tempDic[areaId]];

        
    }
    //省
    self.provinceArray = [tempArray copy];
    
    
    self.provinceIDArray = [tempIDArray copy];
    //市
    self.cityArray = [self getCityNamesFromProvinceIndex:0];
    
    self.cityIDArray = [self getCityIDFromProvinceIndex:0];
    
    
    //区
    self.areaArray = [self getAreaNamesFromProvinceIndex:0 cityIndex:0];
    
    //areaCodeArray
    self.areaCodeArray = [self getAreaareaCodeFromProvinceIndex:0 cityIndex:0];
    
    
    

    //如果没有传入默认选中的省市区,默认选中各个数组的第一个
    if (!self.selectProvince.length) {
        self.selectProvince = [self.provinceArray firstObject];
                               
                               self.selectProvinceID = [self.provinceIDArray firstObject];
        
        
        
        
        
    }
    if (!self.selectCity.length) {
        self.selectCity = [self.cityArray firstObject];
        
        self.selectcityId = self.cityIDArray.firstObject;
        
    }
    if (!self.selectArea.length) {
        self.selectArea = [self.areaArray firstObject];
        self.selectAreaCode = [self.areaCodeArray firstObject];
        
    }
    
    
    
    

    NSInteger provinceIndex = 0;
    NSInteger cityIndex = 0;
    NSInteger areaIndex = 0;
    BOOL isfindarea = NO;// 是否定位到上一次选择的地址
    // 如果上次选择的不是同一数据源,不是统一接口/Area/FindAnyAll返回数据, 这个时候,就无法直接定位到对应的选择地址上。(例如选择的是福建省,而数据源中确是福建)
    for (NSInteger p = 0; p < self.provinceArray.count; p++) {
        if ([self.provinceArray[p] isEqualToString:self.selectProvince]) {
            self.selectProvinceIndex = p;
            provinceIndex = p;
            self.cityArray = [self getCityNamesFromProvinceIndex:p];
            
            self.cityIDArray = [self getCityIDFromProvinceIndex:p];
            
            if(self.showType == CZHAddressPickerViewTypeProvince){
                
                isfindarea = YES;

            }

            

            for (NSInteger c = 0; c < self.cityArray.count; c++) {
                if ([self.cityArray[c] isEqualToString:self.selectCity]) {
                    cityIndex = c;
                    self.areaArray = [self getAreaNamesFromProvinceIndex:p cityIndex:c];
                    
                        self.areaCodeArray = [self getAreaareaCodeFromProvinceIndex:p cityIndex:c];
                    
                    if(self.showType == CZHAddressPickerViewTypeCity){
                        isfindarea = YES;

                    }

                    

                    for (NSInteger a = 0; a < self.areaArray.count; a++) {
                        if ([self.areaArray[a] isEqualToString:self.selectArea]) {
                            areaIndex = a;
                            
                            if(self.showType == CZHAddressPickerViewTypeArea){
                                isfindarea = YES;

                            }
                            
                            
                        }
                    }
                }
            }
        }
    }
    
        // 处理没有匹配到的情况。 如果修改地址没有从接口/Area/FindAnyAll返回的数据,找到对应记录。 这个时候,就无法直接定位到对应的选择地址上。
        
    //
        if(isfindarea == NO){
            
            self.selectProvince = [self.provinceArray firstObject];
                                   
                                   self.selectProvinceID = [self.provinceIDArray firstObject];
            
            self.selectCity = [self.cityArray firstObject];
            
            self.selectcityId = self.cityIDArray.firstObject;
            
            self.selectArea = [self.areaArray firstObject];
            self.selectAreaCode = [self.areaCodeArray firstObject];
            


            

            
        }



    if (self.showType == CZHAddressPickerViewTypeProvince) {
        [self.pickerView selectRow:provinceIndex inComponent:0 animated:YES];
    } else if (self.showType == CZHAddressPickerViewTypeCity) {
        [self.pickerView selectRow:provinceIndex inComponent:0 animated:YES];
        [self.pickerView selectRow:cityIndex inComponent:1 animated:YES];
    } else if (self.showType == CZHAddressPickerViewTypeArea) {
        [self.pickerView selectRow:provinceIndex inComponent:0 animated:YES];
        [self.pickerView selectRow:cityIndex inComponent:1 animated:YES];
        [self.pickerView selectRow:areaIndex inComponent:2 animated:YES];
    }
    
    

}

1.2 didSelectRow

#pragma mark - ******** 滚动省选择市区

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    
    if (component == 0) {//选择省
        self.selectProvinceIndex = row;
        
        if (self.showType == CZHAddressPickerViewTypeProvince) {
            self.selectProvince = self.provinceArray[row];
            self.selectCity = @"";
            self.selectArea = @"";
        } else if (self.showType == CZHAddressPickerViewTypeCity) {
            
            
            
            self.cityArray = [self getCityNamesFromProvinceIndex:row];
            // 重新获取self.cityIDArray
                                    self.cityIDArray = [self getCityIDFromProvinceIndex:row];


            
            [self.pickerView reloadComponent:1];// 市
            
            [self.pickerView selectRow:0 inComponent:1 animated:YES];// 默认选中
            
            self.selectProvince = self.provinceArray[row];
            // 存储self.selectProvinceID
                        self.selectProvinceID = self.provinceIDArray[row];

            self.selectCity = self.cityArray[0];
            self.selectcityId = self.cityIDArray.count? self.cityIDArray[0]:@"";

            self.selectArea = @"";
            
            
            
        } else if (self.showType == CZHAddressPickerViewTypeArea) {
            
            self.cityArray = [self getCityNamesFromProvinceIndex:row];
            self.cityIDArray = [self getCityIDFromProvinceIndex:row];
            self.areaArray = [self getAreaNamesFromProvinceIndex:row cityIndex:0];
            
                self.areaCodeArray = [self getAreaareaCodeFromProvinceIndex:row cityIndex:0];
            
            
            [self.pickerView reloadComponent:1];
            [self.pickerView selectRow:0 inComponent:1 animated:YES];
            [self.pickerView reloadComponent:2];
            [self.pickerView selectRow:0 inComponent:2 animated:YES];
            
            self.selectProvince = self.provinceArray[row];
            
            self.selectProvinceID = self.provinceIDArray[row];
            self.selectcityId = self.cityIDArray.count? self.cityIDArray[0]:@"";
            
            self.selectCity = self.cityArray.count?self.cityArray[0]:@"";
            self.selectArea = self.areaArray.count?self.areaArray[0]:@"";
            self.selectAreaCode = self.areaCodeArray.count?self.areaCodeArray[0]:@"";

        }
    }else if (component == 1){//选择市
        
        if (self.showType == CZHAddressPickerViewTypeCity) {
            
            self.selectCity = self.cityArray[row];
            
            
            self.selectArea = @"";
            
            
        } else if (self.showType == CZHAddressPickerViewTypeArea) {
            
            self.areaArray = [self getAreaNamesFromProvinceIndex:self.selectProvinceIndex cityIndex:row];
            
            
                self.areaCodeArray = [self getAreaareaCodeFromProvinceIndex:self.selectProvinceIndex cityIndex:row];
            
            [self.pickerView reloadComponent:2];
            [self.pickerView selectRow:0 inComponent:2 animated:YES];
            self.selectCity = self.cityArray[row];
            self.selectcityId = self.cityIDArray[row];
            self.selectArea = self.areaArray.count?self.areaArray[0]:@"";
            self.selectAreaCode = self.areaCodeArray.count?self.areaCodeArray[0]:@"";

        }
    }else if (component == 2){//选择区
        
        if (self.showType == CZHAddressPickerViewTypeArea) {
            
            
            if(self.areaArray.count == 0){
                self.selectArea = @" ";
                self.selectAreaCode = @" ";

            }else{
                self.selectArea = self.areaArray[row];
                self.selectAreaCode = self.areaCodeArray[row];
                


            }
            
        }
    }
}

1.3 初始化方法

#pragma mark - ******** 选择省和市
+ (instancetype)newaddressPickerViewWithProvince:(NSString *)province city:(NSString *)city  provinceId:(NSString*)provinceId cityId:(NSString*)cityId  cityBlock:(void(^)(NSString *province, NSString *city ,NSString* provinceId,NSString *cityId))cityBlock  showType:(CZHAddressPickerViewType)showType{
    
    
    CZHAddressPickerView *_view = [[CZHAddressPickerView alloc] init];
    
    _view.showType = showType;
    
    _view.selectProvince = province;
    _view.selectProvinceID = provinceId;

    _view.selectCity = city;
    _view.selectcityId = cityId;
    _view.cityidBlock  = cityBlock;

    
#pragma mark - ******** 获取原始数据
    
    
    [_view czh_getData];
    
    [_view showView];
    
    return _view;
    
}

1.4 工具方法: 获取每个component的数据

1.4.1 获取城市数据

  • 根据row获取城市id数组
//获取城市id数组
- (NSArray *)getCityIDFromProvinceIndex:(NSInteger)provinceIndex
{
    NSArray * tempArr = [self.dataSource[provinceIndex] objectForKey:cities];
    NSMutableArray * cityArray = [NSMutableArray array];
    for (NSDictionary * valueDic in tempArr) {
        
        
        [cityArray addObject:valueDic[self.areaId]];
        
        
    }
    return [cityArray copy];
}

  • 获取城市数组
//获取城市数组
- (NSArray *)getCityNamesFromProvinceIndex:(NSInteger)provinceIndex
{
    NSArray * tempArr = [self.dataSource[provinceIndex] objectForKey:cities];
    NSMutableArray * cityArray = [NSMutableArray array];
    for (NSDictionary * valueDic in tempArr) {
        
//        for (int i = 0; i < valueDic.allKeys.count; i ++) {
            [cityArray addObject:valueDic[areaName]];
//        }
    }
    return [cityArray copy];
}


1.4.2 获取区域数据

  • 获取区域ID数组
//获取区域ID数组
- (NSArray *)getAreaareaCodeFromProvinceIndex:(NSInteger)provinceIndex cityIndex:(NSInteger)cityIndex
{
    
    NSArray * tempArr = [self.dataSource[provinceIndex] objectForKey:cities];
    NSMutableArray * array = [NSMutableArray array];
    
    if (tempArr.count) {
        NSArray * cityArr = [tempArr[cityIndex] objectForKey:cities];
        for (NSDictionary * valueDic in cityArr) {
            [array addObject:valueDic[self.areaId]];//areaCode
            
        }
        return [array copy];
    }else{
        return @[];
    }
    
}

-获取区域数组

- (NSArray *)getAreaNamesFromProvinceIndex:(NSInteger)provinceIndex cityIndex:(NSInteger)cityIndex
{

    NSArray * tempArr = [self.dataSource[provinceIndex] objectForKey:cities];
    NSMutableArray * array = [NSMutableArray array];
    
    if (tempArr.count) {
        NSArray * cityArr = [tempArr[cityIndex] objectForKey:cities];
        for (NSDictionary * valueDic in cityArr) {
            [array addObject:valueDic[areaName]];
        }
        return [array copy];
    }else{
        return @[];
    }
    
}


1.4.3获取省份数据,用于选择组件视图

    NSMutableArray * tempArray = [NSMutableArray array];
    NSMutableArray * tempIDArray = [NSMutableArray array];

    for (NSDictionary * tempDic in self.dataSource) {
        [tempArray addObject:tempDic[areaName]];
        [tempIDArray addObject:tempDic[self.areaId]];

        
    }
    //省
    self.provinceArray = [tempArray copy];
    
    
    self.provinceIDArray = [tempIDArray copy];

II、设置UIPickerView的选中横线的颜色(设置白色可达到隐藏的效果)

kunnan.blog.csdn.net/article/det…

see also

city.json 数据

  • city.json
[{
		"parentId": "1",
		"areaSN": "",
		"postCode": "",
		"sort": 3,
		"areaCode": "120000",
		"id": "4",
		"quanPin": "tianjin",
		"childItems": [{
			"parentId": "4",
			"areaSN": "022",
			"postCode": "300000",
			"sort": 1,
			"areaCode": "120100",
			"id": "305",
			"quanPin": "tianjin",
			"childItems": [{
					"parentId": "305",
					"areaSN": "",
					"postCode": "300000",
					"sort": 1,
					"areaCode": "120101",
					"id": "311",
					"quanPin": "heping",
					"childItems": null,
					"jianPin": "hp",
					"areaName": "和平区"
				},

  • city.plist