免费开源的iOS开发学习平台

UIPickerView详解:3-相互依赖的多列选择器

在实际开发过程中,选择器的形式一般都不止一列,例如我们会碰到这样的情况,选择器中第二列的列表项需要依赖于第一列的选择,即当第一列选择某个列表项的时候,第二列只显示第一列所选的列表项对应的内容。比如省份与城市相关联的选择器。此篇文章我们通过一个简单的实例来实现这种效果。

准备工作

  • 在控制器类中,添加需要使用的属性,并设置控制器类遵守UIPickerViewDataSource以及UIPickerViewDelegate协议。其中,dictionary用于存放需要展示的数据项,provinceArray是用来存放第一列省份数据的数组,selectedProvince是第一列中选中的数据,即选中的省份。
@interface ViewController ()<UIPickerViewDataSource,UIPickerViewDelegate>
@property (nonatomic, strong) UIPickerView *pickerView;
@property (nonatomic, strong) NSDictionary *dictionary;
@property (nonatomic, strong) NSArray *provinceArray;
@property (nonatomic, strong) NSString *selectedProvince;
@end
  • 实例化dictionary属性,用于设置将在选择器上显示的数据。
- (NSDictionary *)dictionary {
    if (_dictionary == nil) {
        _dictionary = @{@"江苏": @[@"南京",@"徐州",@"镇江",@"无锡",@"常州"],@"河北":@[@"石家庄",@"保定",@"承德",@"沧州",@"秦皇岛"]};
    }
    return _dictionary;
}
  • 初始化UIPickerView对象,对其外观属性进行简单定制,并设置其数据源对象以及代理对象为本控制器
- (UIPickerView *)pickerView {
    if (_pickerView == nil) {
        _pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 193, 375, 216)];
        _pickerView.dataSource = self;
        _pickerView.delegate = self;
    }
    return _pickerView;
}
  • 在viewDidLoad方法中添加子控件到控制器view上,并且使用provinceArray保存dictionary中所有键值(即需要展示的省份名称),并设置默认选中的省份是provinceArray中的第一个元素。
- (void)viewDidLoad {
    [super viewDidLoad];
    self.provinceArray = [[self.dictionary allKeys] sortedArrayUsingSelector:@selector(compare:)];
    self.selectedProvince = self.provinceArray[0];
    [self.view addSubview:self.pickerView];
}

实现UIPickerViewDataSource中的方法

  • 设置选择器列数,由于需要展示省市两级,因此我们需要两列
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 2;
}
  • 设置各列中将要展示的数据的个数,如果是第一列返回provinceArray中元素的个数,如果是第二列则返回dictionaryselectedProvince对应的元素个数,即不同省份中的城市的个数。
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    if (component == 0) {
        return self.provinceArray.count;
    }
    return [self.dictionary[self.selectedProvince] count];
}

实现UIPickerViewDelegate中的方法

返回指定列和选项上显示的标题,第一列展示省份信息,第二列根据selectedProvince的值返回对应省份的地市名称。

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {  
    if (component == 0) {
        return self.provinceArray[row];
    }
    return [self.dictionary[self.selectedProvince] objectAtIndex:row];
}

当选中指定省份时,改变selectedProvince中的值,根据选中的省份重新加载第二个列表,并且设置第二列中首选标记的元素始终是第一个。

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    if (component == 0) {
        self.selectedProvince = self.provinceArray[row];
        [self.pickerView reloadComponent:1];
        [self.pickerView selectRow:0 inComponent:1 animated:YES];
    }
}

运行效果:

示例代码

https://github.com/99ios/10.4.3