【iOS】UIPickerView -- 地址选择器:省/市/区

BUG -- 在选择海南省的时候,有的市是没有区的,导致程序会因为数组越界的问题而崩溃.

BUG 问题已经解决,具体怎么解决这里不再修改代码了.

更新:2016.03.05  修复选择海南有的市下面没有区导致崩溃的bug.

缘由

由于项目的需要,需要对之前的地址选择器做改进。之前的地址选择器只能显示地址的省市区的名字等信息,不能显示其他ID类的信息。这次改进是使用新的数据源,关于数据源从后台获取和写入数据库我就不仔细说明了,代码里面有请自己查看(只有数据库部分)。后台那边给的数据是三个大数组,分别:省、市、区,所以数据库里面就分别把省市区各做了一张表也就是三张表存储的。


这次也是第一次使用UIPickerView,刚开始还不知怎么入手,但是看着博客后,使用起来感觉和UITableView差不多,都是两个代理UIPickerViewDataSource,UIPickerViewDelegate,都有选择方法等。

效果图

这次修改保持了上项目中得上一版的界面的一致性,主要的差别就是选择的结果的信息更加丰富。

先看看demo的界面(不是项目截图)和git截图:左边是手机6的截图,右边是模拟器截的gif。


具体使用

那么这个地址选择器怎么使用呢?

其实也就是四步:

第一步:包含头文件

#import "ChinaPlckerView.h"

第二步:增加代理

@interface ViewController ()<ChinaPlckerViewDelegate>

第三步:添加视图

/**
 *  点击按钮显示地址选择器
 *
 *  @param sender sender description
 */
- (IBAction)btnClick:(UIButton *)sender {
    [ChinaPlckerView customChinaPicker:self superView:self.view];
}

第四步:实现代理

代理里面做的demo现实数据的显示

#pragma mark - ChinaPlckerViewDelegate
- (void)chinaPlckerViewDelegateChinaModel:(ChinaArea *)chinaModel{
    // 省
    self.provinceLabel.text = [NSString stringWithFormat:@"NAME:%@ ID:%@ GRADE:%@ PARENT_AREA_ID:%@",chinaModel.provinceModel.NAME,chinaModel.provinceModel.ID,chinaModel.provinceModel.GRADE,chinaModel.provinceModel.PARENT_AREA_ID];
    // 市
    self.cityLabel.text = [NSString stringWithFormat:@"NAME:%@ ID:%@ GRADE:%@ PARENT_AREA_ID:%@",chinaModel.cityModel.NAME,chinaModel.cityModel.ID,chinaModel.cityModel.GRADE,chinaModel.cityModel.PARENT_AREA_ID];
    // 区
    self.areaLabel.text = [NSString stringWithFormat:@"NAME:%@ ID:%@ GRADE:%@ PARENT_AREA_ID:%@",chinaModel.areaModel.NAME,chinaModel.areaModel.ID,chinaModel.areaModel.GRADE,chinaModel.areaModel.PARENT_AREA_ID];
}
整个数据的显示部分是使用xib做的所以代码量不多。

控件的实现

由于使用了数据库,这里使用的FMDB,没有使用CoreData或是SQLite3。(FMDB的实质也就是SQLite3)。关于FMDB和SQLite3的使用可以看我的博客《【iOS】数据库FMDB的使用(一)》《【iOS】数据库FMDB的使用(二)》《【iOS】数据库SQLite3的使用》。这里略。

控件的结构

ChinaPlckerView.h和ChinaPlckerView.m是视图的显示部分。

ChinaArea.h和ChinaArea.m是数据库部分。

其他三个**Model的分别是省市区的数据模型,里面的四个属性是一样的。

china_citys_name.db是本地的数据库。

视图的具体实现代码:

<pre name="code" class="objc">//
//  ChinaPlckerView.m
//  地址选择器
//
//  Created by zhuming on 16/2/15.
//  Copyright © 2016年 zhuming. All rights reserved.
//

#import "ChinaPlckerView.h"

// 屏幕的高度
#define kScreenHeight [[UIScreen mainScreen] bounds].size.height

// 屏幕的宽度
#define kScreenWidth [[UIScreen mainScreen] bounds].size.width

//键盘高度 253
#define IT_KEYBOARD_HEIGHT 253

#define ROW_HEIGHT  30

//设置RGB颜色值
#define COLOR(R,G,B,A)	[UIColor colorWithRed:(CGFloat)R/255.0 green:(CGFloat)G/255.0 blue:(CGFloat)B/255.0 alpha:A]

@interface ChinaPlckerView ()<UIPickerViewDataSource,UIPickerViewDelegate>
/**
 *  地址选择器
 */
@property (nonatomic,strong)UIPickerView *pickerView;
/**
 *  确定按钮
 */
@property (nonatomic,strong)UIButton *sureButton;
/**
 *  蒙蔽曾
 */
@property (nonatomic,strong)UIView *hideView;
/**
 *  选择器视图
 */
@property (nonatomic,strong)UIView *addPickVview;
/**
 *  数据模型
 */
@property (nonatomic,strong)ChinaArea *chinaModel;
/**
 *  选择的省份ID
 */
@property (nonatomic,strong)NSString *selectedProvinceID;
/**
 *  选择的城市ID
 */
@property (nonatomic,strong)NSString *selectedCityID;
/**
 *  选择的区域ID
 */
@property (nonatomic,strong)NSString *selectedAreaID;

@end

@implementation ChinaPlckerView

/**
 *  添加城市选择器
 *
 *  @param delegate 代理
 *  @param views    父视图
 *
 *  @return 城市选择器
 */
+(ChinaPlckerView *)customChinaPicker:(id)delegate superView:(UIView*)views{
    
    UIView *oldView = [views viewWithTag:0x123];
    if ([oldView isKindOfClass:[ChinaPlckerView class]]) {
        ChinaPlckerView *navView =  (ChinaPlckerView *)oldView;
        navView.delegate = delegate;
        [navView showChinaPickerView];
        return navView;
    }
    ChinaPlckerView *navView = [[ChinaPlckerView alloc] init];
    navView.delegate = delegate;
    [navView showChinaPickerView];
    navView.tag = 0x123;
    [views addSubview:navView];
    return navView;
}
/**
 *  重写父类的init方法
 *
 *  @return self
 */
- (instancetype)init{
    if (self = [super init]) {
        [self initPickerView];
    }
    return self;
}
/**
 *  确定按钮按下
 */
- (void)btnClick{
    if ([_delegate respondsToSelector:@selector(chinaPlckerViewDelegateChinaModel:)]) {
        [_delegate chinaPlckerViewDelegateChinaModel:self.chinaModel];
    }
    [self hideChinaPickerView];
}
/**
 *  触摸屏幕其他地方收起选择器
 */
- (void)tapClick{
    [self hideChinaPickerView];
}
/**
 *  创建城市选择器
 */
- (void)initPickerView{
    // 模型的初始化
    self.chinaModel = [[ChinaArea alloc] init];
    
    // 默认
    self.selectedProvinceID = @"2";  // 北京市
    self.selectedCityID = @"52";     // 北京市
    self.selectedAreaID = @"500";    // 东城区
    
    self.chinaModel.provinceModel = ((ProvinceModel *)[self.chinaModel getProvinceDataByID:self.selectedProvinceID]);
    self.chinaModel.cityModel = ((CityModel *)[self.chinaModel getCityDataByID:self.selectedCityID]);
    self.chinaModel.areaModel = ((AreaModel *)[self.chinaModel getAreaDataByID:self.selectedAreaID]);
    
    // 初始化视图
    self.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
    self.userInteractionEnabled = YES;
    self.hidden = YES;
    self.backgroundColor = [UIColor clearColor];
    // 蒙蔽层
    self.hideView = [[UIView alloc] init];
    self.hideView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
    self.hideView.backgroundColor = COLOR(45, 47, 56, 0.0f);
    [self addSubview:self.hideView];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapClick)];
    [self.hideView addGestureRecognizer:tap];
    //添加选择器
    self.addPickVview = [[UIView alloc]init];
    self.addPickVview.frame = CGRectMake(0,  kScreenHeight -  IT_KEYBOARD_HEIGHT, kScreenWidth, IT_KEYBOARD_HEIGHT);
    self.addPickVview.backgroundColor = [UIColor whiteColor];
    [self addSubview:self.addPickVview];
    //确认按钮
    CGFloat titleHeight =  IT_KEYBOARD_HEIGHT - 216;
    UIView *titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,kScreenWidth,titleHeight)];
    //titleView.backgroundColor = [UIColor blueColor];
    [self.addPickVview addSubview:titleView];
    
    UIButton *sureBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    sureBtn.frame = CGRectMake(kScreenWidth - 70, 0, 60, titleHeight);
    [sureBtn setTitle:@"确定" forState:UIControlStateNormal];
    [sureBtn setTitle:@"确定" forState:UIControlStateHighlighted];
    [sureBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [sureBtn setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted];
    [sureBtn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
    [titleView addSubview:sureBtn];
    // UIPickerView
    UIPickerView  *pickerView = [[UIPickerView alloc] init];
    pickerView.frame = CGRectMake(0, CGRectGetMaxY(titleView.frame), kScreenWidth, 216);
    pickerView.delegate = self;
    pickerView.dataSource = self;
    pickerView.backgroundColor = [UIColor whiteColor];
    [self.addPickVview addSubview:pickerView];
    self.pickerView = pickerView;
    
    [self.pickerView selectRow:0 inComponent:0 animated:YES];
    [self.pickerView selectRow:0 inComponent:1 animated:YES];
    [self.pickerView selectRow:0 inComponent:2 animated:YES];
}
#pragma mark - UIPickerViewDataSource,UIPickerViewDelegate
/**
 *  设置pickerView的列数
 *
 *  @param pickerView pickerView description
 *
 *  @return pickerView的列数
 */
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 3;
}
/**
 *  设置每一列显示的数量
 *
 *  @param pickerView pickerView description
 *  @param component  列
 *
 *  @return 美列的数量
 */
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    if (component == 0) { // 省份
        return [self.chinaModel getAllProvinceData].count;
    }
    else if (component == 1){ // 城市
        return [self.chinaModel getCityDataByParentID:self.selectedProvinceID].count;
    }
    else{ // 区域
        return [self.chinaModel getAreaDataByParentID:self.selectedCityID].count;
    }
}
/**
 *  设置每一列的宽度
 *
 *  @param pickerView pickerView description
 *  @param component  列
 *
 *  @return 每列的宽度
 */
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
    return (kScreenWidth - 20)/3;
}
/**
 *  设置每一行的高度
 *
 *  @param pickerView pickerView description
 *  @param component  列
 *
 *  @return 每一行的高度
 */
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
    return ROW_HEIGHT;
}
/**
 *  设置每一行的显示视图
 *
 *  @param pickerView pickerView description
 *  @param row        每一类的row
 *  @param component  列
 *  @param view       view description
 *
 *  @return 每一列每一行的视图
 */
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
    if (component == 0) { // 省份
        if (!view) {
            view = [[UIView alloc] init];
        }
        UILabel *textLabel = [[UILabel alloc] init];
        textLabel.frame = CGRectMake(0, 0, (kScreenWidth - 20)/3, ROW_HEIGHT);
        textLabel.textAlignment = NSTextAlignmentCenter;
        textLabel.text = ((ProvinceModel *)[self.chinaModel getAllProvinceData][row]).NAME;
        textLabel.font = [UIFont systemFontOfSize:14];
        textLabel.textColor = COLOR(51, 51, 51, 1);
        [view addSubview:textLabel];
        return view;
    }
    else if (component == 1){ // 城市
        if (!view) {
            view = [[UIView alloc] init];
        }
        UILabel *textLabel = [[UILabel alloc] init];
        textLabel.frame = CGRectMake(0, 0, (kScreenWidth - 20)/3, ROW_HEIGHT);
        textLabel.textAlignment = NSTextAlignmentCenter;
        textLabel.text = ((CityModel *)[self.chinaModel getCityDataByParentID:self.selectedProvinceID][row]).NAME;
        textLabel.font = [UIFont systemFontOfSize:14];
        textLabel.textColor = COLOR(51, 51, 51, 1);
        [view addSubview:textLabel];
        return view;
    }
    else{ // 区域
        if (!view) {
            view = [[UIView alloc] init];
        }
        UILabel *textLabel = [[UILabel alloc] init];
        textLabel.frame = CGRectMake(0, 0, (kScreenWidth - 20)/3, ROW_HEIGHT);
        textLabel.textAlignment = NSTextAlignmentCenter;
        textLabel.text = ((AreaModel *)[self.chinaModel getAreaDataByParentID:self.selectedCityID][row]).NAME;
        textLabel.font = [UIFont systemFontOfSize:14];
        textLabel.textColor = COLOR(51, 51, 51, 1);
        [view addSubview:textLabel];
        return view;
    }
}
/**
 *  pickerView选中代理
 *
 *  @param pickerView pickerView description
 *  @param row        选中的row
 *  @param component  列
 */
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    switch (component) {
        case 0:{ // 选择省份
            self.selectedProvinceID = ((ProvinceModel *)[self.chinaModel getAllProvinceData][row]).ID;
            [pickerView reloadComponent:1]; // 重载城市
            [pickerView selectRow:0 inComponent:1 animated:YES];
            self.chinaModel.provinceModel = (ProvinceModel *)[self.chinaModel getAllProvinceData][row];
            // 选择了省份就自动定位到该省的第一个市
            self.selectedCityID = ((CityModel *)[self.chinaModel getCityDataByParentID:self.selectedProvinceID][0]).ID;
            self.chinaModel.cityModel = (CityModel *)[self.chinaModel getCityDataByParentID:self.selectedProvinceID][0];
            
            // 选择了省份就自动定位到该省的第一个市的第一个区
            [pickerView  reloadComponent:2]; // 重载区域
            [pickerView selectRow:0 inComponent:2 animated:YES];
            // 海南 有的市没有区  真是坑啊
            if ([self.chinaModel getAreaDataByParentID:self.selectedCityID].count > 0) {
                self.chinaModel.areaModel = (AreaModel *)[self.chinaModel getAreaDataByParentID:self.selectedCityID][0];
            }
            else{
                self.chinaModel.areaModel.NAME = @"";
                self.chinaModel.areaModel.ID = @"";
                self.chinaModel.areaModel.PARENT_AREA_ID = @"9";
                self.chinaModel.areaModel.GRADE = @"3";
            }
            break;
        }
        case 1:{ // 选择城市
            self.selectedCityID = ((CityModel *)[self.chinaModel getCityDataByParentID:self.selectedProvinceID][row]).ID;
            [pickerView  reloadComponent:2]; // 重载区域
            [pickerView selectRow:0 inComponent:2 animated:YES];
            self.chinaModel.cityModel = (CityModel *)[self.chinaModel getCityDataByParentID:self.selectedProvinceID][row];
            // 选择了市就定位到该市的第一个区
            // 海南 有的市没有区  真是坑啊
            if ([self.chinaModel getAreaDataByParentID:self.selectedCityID].count > 0) {
                self.chinaModel.areaModel = (AreaModel *)[self.chinaModel getAreaDataByParentID:self.selectedCityID][0];
            }
            else{
                self.chinaModel.areaModel.NAME = @"";
                self.chinaModel.areaModel.ID = @"";
                self.chinaModel.areaModel.PARENT_AREA_ID = @"9";
                self.chinaModel.areaModel.GRADE = @"3";
            }
            
            break;
        }
        case 2: // 选择区域
            // 海南 有的市没有区  真是坑啊
            if ([self.chinaModel getAreaDataByParentID:self.selectedCityID].count > 0) {
                self.chinaModel.areaModel = (AreaModel *)[self.chinaModel getAreaDataByParentID:self.selectedCityID][row];
            }
            else{
                self.chinaModel.areaModel.NAME = @"";
                self.chinaModel.areaModel.ID = @"";
                self.chinaModel.areaModel.PARENT_AREA_ID = @"9";
                self.chinaModel.areaModel.GRADE = @"3";
            }
            break;
        default:
            break;
    }

    if ([_delegate respondsToSelector:@selector(chinaPlckerViewDelegateChinaModel:)]) {
        [_delegate chinaPlckerViewDelegateChinaModel:self.chinaModel];
    }
}

#pragma mark - 显示
-(void)showChinaPickerView
{
    [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
    self.hidden = NO;
    [UIView animateWithDuration:0.25f animations:^{
        float pikceY =  kScreenHeight - IT_KEYBOARD_HEIGHT;
        self.addPickVview.frame = CGRectMake(0, pikceY, kScreenWidth, IT_KEYBOARD_HEIGHT);
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.25f animations:^{
            self.hideView.backgroundColor = COLOR(45, 47, 56, 0.2f);
        } completion:^(BOOL finished) {
            
        }];
    }];
}
#pragma mark - 隐藏
-(void)hideChinaPickerView
{
    [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
    [UIView animateWithDuration:0.25f animations:^{
        float pikceY =  kScreenHeight;
        self.addPickVview.frame = CGRectMake(0, pikceY, kScreenWidth, IT_KEYBOARD_HEIGHT);
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.25f animations:^{
            self.hideView.backgroundColor = COLOR(45, 47, 56, 0.0f);
        } completion:^(BOOL finished) {
            self.hidden = YES;
        }];
    }];
    
    if ([_delegate respondsToSelector:@selector(chinaPickerViewDelegateHidden)]) {
        [_delegate chinaPickerViewDelegateHidden];
    }
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end

 关于UIPickerView的使用,代码中有注释,详细使用可以自行查找相关文章。 

其他几个文件就不多说明了。

代码的下载地址。下载请点击我。


/** * 只显示份一级 * provinceBlock : 回调份 */ (instancetype)provincePickerViewWithProvinceBlock:(void(^)(NSString *province))provinceBlock; /** * 显示份和级 * cityBlock : 回调份和城 */ (instancetype)cityPickerViewWithCityBlock:(void(^)(NSString *province, NSString *city))cityBlock; /** * 显示份和级和域 * areaBlock : 回调份城域 */ (instancetype)areaPickerViewWithAreaBlock:(void(^)(NSString *province, NSString *city, NSString *area))areaBlock; /** * 只显示份一级 * province : 传入了份自动滚动到份,没有传或者找不到默认选中第一个 * provinceBlock : 回调份 */ (instancetype)provincePickerViewWithProvince:(NSString *)province provinceBlock:(void(^)(NSString *province))provinceBlock; /** * 显示份和级 * province,city : 传入了份和城自动滚动到选中的,没有传或者找不到默认选中第一个 * cityBlock : 回调份和城 */ (instancetype)cityPickerViewWithProvince:(NSString *)province city:(NSString *)city cityBlock:(void(^)(NSString *province, NSString *city))cityBlock; /** * 显示份和级和域 * province,city : 传入了份和城域自动滚动到选中的,没有传或者找不到默认选中第一个 * areaBlock : 回调份城域 */ (instancetype)areaPickerViewWithProvince:(NSString *)province city:(NSString *)city area:(NSString *)area areaBlock:(void(^)(NSString *province, NSString *city, NSString *area))areaBlock;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值