UIPickerView实现两级联动

作者: COMMA_迷途知返 | 来源:发表于2019-04-04 23:51 被阅读1次

    黑马程序员UI进阶教程第一天案例(省市名称的选择和显示)总结

    该案例主要实现省市的显示和选择,当左侧省变化之后,右侧相应的市的名称也相应变化,并且将选择结果显示在两个文本框中。主要的实现思路如下:

    1. 绘制界面,导入素材,字典转模型,懒加载

    2. 实现pickerView的数据源方法和代理方法,使数据显示出来

    3. 在pickerView的代理方法-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component中写代码,使省市的名称显示在两个label中

    4. 实现pickerView的及时刷新

    5. 修复pickerView两列同时滚动时索引越界的bug

      最终效果如下:

      最终效果

    1.绘制界面,导入素材,字典转模型,懒加载

    2.实现pickerView的数据源方法和代理方法,使数据显示出来

    要使pickerView显示出文本数据,至少需要实现如下三个方法:

    //数据源方法,返回需要显示的数据一共有几列
    -(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
    {
        return 2;
    }
    //数据源方法,返回某一列对应的行数
    -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
    {
        if (component == 0) {
          //当为第一列时,返回provinces数组的个数,即为省的行数
            return self.provinces.count;
        } else {
          //当为第二列时,需要先获取当前第一列选中的行号的索引,然后根据索引获取对应的cities数组,返回这个数组的个数,即为城市的行数
            NSUInteger province_row = [self.pickV_provinceView selectedRowInComponent:0];
            LJProvince * province_current = self.provinces[province_row];
            return province_current.cities.count;
        }
    }
    //代理方法,返回某一列某一行应该显示的文本字符串
    -(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
    {
        if (component == 0) {
          //如果是第一列,直接返回对应行号索引的省的名称
            return [self.provinces[row] name];
        } else {
          //当为第二列时,需要先获取当前第一列选中的行号的索引,然后根据索引获取对应的cities数组,再根据参数中行号索引返回对应城市的名称
            NSUInteger province_row = [self.pickV_provinceView selectedRowInComponent:0];
            LJProvince * province_current = self.provinces[province_row];
            return province_current.cities[row];
        }
    }
    

    3.使省市的名称显示在两个label中

    使用代理方法

    -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
    {   
      //获取当前所选的第一列的行号
        NSUInteger province_row = [self.pickV_provinceView selectedRowInComponent:0];
      //获取当前所选的第二列的行号
        NSUInteger city_row = [self.pickV_provinceView selectedRowInComponent:1];
      //根据第一列行号索引获取当前省的数据
        LJProvince * province_current = self.provinces[province_row];
      //分别将省的名称和城市的名称赋值给两个label
        self.lbl_province.text = province_current.name;
        self.lbl_city.text = province_current.cities[city_row];
    }
    

    4.实现pickerView的及时刷新

    当显示pickerView的数据了之后我们发现,滚动省的那一列,对应的城市名称并不会立即刷新,而是需要把城市的那一列也滚动一下才能刷新数据,这是因为当我们滚动省的那一列时,系统并不会自动调用城市那一列的代理方法来更新数据,解决方法就是当我们选择了数据之后强制让pickerView刷新数据

    -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
    {
        if (component == 0) {
          //当滚动的是省的那一列时,手动刷新城市那一列的数据
            [self.pickV_provinceView reloadComponent:1];
        }   
    //其它代码
    }
    

    5.修复pickerView两列同时滚动时索引越界的bug

    数据显示正常以后,当我们同时滚动两列数据时程序会发生崩溃,系统提示索引越界

    根本原因是我们在返回文本和为label赋值时,都是通过实时获取当前的省份对应的城市名称来返回的。假如初始状态两列显示的都是第0行,当我们同时滚动两列数据时,假如某一时刻第一列滚动到了第5行,第二列滚动到了第10行,此时系统调用代理方法就会根据第一列的行号5来获取第二列的数据并返回行号为10的城市名称,但如果行号为5的省份对应的城市数量只有9个,那么此时就会造成索引越界。

    案例中的解决方案为在最开始返回省份信息时就通过一个变量将其保存下来,返回城市名称时不再实时获取当前的省份的行号,而是通过存储的省份行号来确定城市的信息,这样就会避免索引越界的问题

    //用于存储选择的省份信息
    @property(nonatomic , weak) LJProvince * province_select;
    
    //数据源方法,返回某一列的行数
    -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
    {
        if (component == 0) {
            return self.provinces.count;
        } else {
            NSUInteger province_row = [self.pickV_provinceView selectedRowInComponent:0];
            LJProvince * province_current = self.provinces[province_row];
          //将当前的省份信息
            self.province_select = province_current;
            return province_current.cities.count;
        }
    }
    //代理方法,返回某一列某一行的文本字符串
    -(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
    {
        if (component == 0) {
            return [self.provinces[row] name];
        } else {
                //直接使用保存的省份信息来返回城市名称
            return self.province_select.cities[row];
        }
    }
    
    -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
    {
        if (component == 0) {
            [self.pickV_provinceView reloadComponent:1];
        }
        NSUInteger city_row = [self.pickV_provinceView selectedRowInComponent:1];
      //通过保存的省份数据来返回省份名称和城市名称
        self.lbl_province.text = self.province_select.name;
        self.lbl_city.text = self.province_select.cities[city_row];
    }
    
    

    由于本人水平有限,不当之处还请批评指正。初学IOS,希望大家一起交流一起进步~

    相关文章

      网友评论

        本文标题:UIPickerView实现两级联动

        本文链接:https://www.haomeiwen.com/subject/sbwciqtx.html