天天看點

UIPickerView實作兩級關聯

黑馬程式員UI進階教程第一天案例(省市名稱的選擇和顯示)總結

該案例主要實作省市的顯示和選擇,當左側省變化之後,右側相應的市的名稱也相應變化,并且将選擇結果顯示在兩個文本框中。主要的實作思路如下:

  1. 繪制界面,導入素材,字典轉模型,懶加載
  2. 實作pickerView的資料源方法和代理方法,使資料顯示出來
  3. 在pickerView的代理方法

    -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

    中寫代碼,使省市的名稱顯示在兩個label中
  4. 實作pickerView的及時重新整理
  5. 修複pickerView兩列同時滾動時索引越界的bug

    最終效果如下:

    UIPickerView實作兩級關聯

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,希望大家一起交流一起進步~