金陵子弟來相送,欲行不行各盡觴!<地幔巖>

簡單說幾句:
UIDatePicker:
1: 直接繼承 UIControl (那么就可以有 addTarget ........的方法使用 可以添加相應(yīng)的觸發(fā)事件)
2: 可以用來選擇作為時間選擇器, 通過 datePickerMode 選擇樣式效果
3: 使用比較多的屬性可以點(diǎn)進(jìn)去看下一般就是 date(當(dāng)前的表示日期 NSDate 類型) locale( 選擇語言 zh 中文 en 英文)
UIPickerView:
1: 直接繼承與 UIView 在使用上與 tabelView 有很多類似之處
2: 完美的使用要依賴代理實(shí)現(xiàn)兩個協(xié)議<UIPickerViewDelegate, UIPickerViewDataSource>
3: 其他的搜集到了再補(bǔ)充
看一下 UI 的外觀展示


下面我們簡單實(shí)現(xiàn)一下一個選擇日期和選擇地址的效果
這里我用兩個 textFile 作為輸入框接收我們?nèi)掌诤偷刂沸Ч麍D如下, 在一些注冊和購物選址地方會出現(xiàn)使用
效果圖如下:

解析思路難點(diǎn):
1: 兩個 textFile 點(diǎn)擊后的彈出的默認(rèn)鍵盤 分別替換成 UIDatePicker 和 UIPickerView 作為輸入
2: 通過鍵盤的代理方法來控制鍵盤的輸入問題
3: 地址的處理容易三級聯(lián)動過程中容易出現(xiàn)數(shù)組越界問題, 我這里解決不知道完美不, 有更好的方法還請簡友多幫助我.
上代碼:
需要的屬性:
@interface ViewController ()<UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
@property (weak, nonatomic) IBOutlet UITextField *timeField;// 時間輸入
@property (weak, nonatomic) IBOutlet UITextField *addressFiled;// 地址輸入
@property (strong, nonatomic) UIDatePicker *dateKB;// 日期鍵盤
@property (strong, nonatomic) UIPickerView *addressKB;// 地址鍵盤
@property (strong, nonatomic) NSMutableArray<province_Model *> *allProvinceArray;// 存放所有的數(shù)據(jù)
# 下面幾個數(shù)據(jù)為了防止同時滑動多個列的時候 某個列數(shù)據(jù)獲取時候數(shù)組越界導(dǎo)致崩潰
@property (assign, nonatomic) NSInteger provinceCurrentIndex;// 用來記錄''當(dāng)前''的省份下標(biāo)(地址鍵盤第 0 列選中 row))
@property (assign, nonatomic) NSInteger cityCurrentIndex; // 用來記錄''當(dāng)前''的城市的下標(biāo)(地址鍵盤第 1 列選中的 row)
@property (assign, nonatomic) NSInteger countyCurrenIndex; // 記錄縣
@end
我這里使用了兩個 Model 類
# province_Model
@property (copy, nonatomic) NSString *provinceName;
@property (strong, nonatomic) NSMutableArray<city_Model *> *cityArray;
# city_Model
@property (copy, nonatomic) NSString *cityName;
@property (strong, nonatomic) NSMutableArray *countyArray;
在 viewDidLoad 中設(shè)置一些基本的參數(shù):
// 設(shè)置代理
self.timeField.delegate = self;
self.addressFiled.delegate = self;
// 初始化日期鍵盤
self.dateKB = [UIDatePicker new];
_dateKB.datePickerMode = UIDatePickerModeDate; // 設(shè)置模式 這里是 年月日 沒有上下午
_dateKB.locale = [NSLocale localeWithLocaleIdentifier:@"zh"]; // 設(shè)置地區(qū) 這里是
self.timeField.inputView = _dateKB; // 用 UIDatePicker 替換 timeField 的鍵盤
// 當(dāng)值改變的時候會觸發(fā)的方法 我們滑動日期鍵盤的時候 執(zhí)行方法 rollAction:
[_dateKB addTarget:self action:@selector(rollAction:) forControlEvents:(UIControlEventValueChanged)];
// 初始化地址鍵盤
self.addressKB = [UIPickerView new];
self.addressKB.delegate = self;
self.addressKB.dataSource = self;
self.addressFiled.inputView = self.addressKB; // 用 UIPickerView 替換 addressFiled輸入鍵盤
// 解析數(shù)據(jù)
self.allProvinceArray = [NSMutableArray array]; // 存放所有的省份
// 調(diào)用 自定義的 從 plist 析數(shù)據(jù)方法
[self getDataForPlist];
數(shù)據(jù)的結(jié)構(gòu)如圖: 感謝網(wǎng)友的分享的 plist 的文件有需要的可以下載使用鏈接: 密碼: 2pdf

#pragma mark ------>> 解析數(shù)據(jù) <<------
- (void)getDataForPlist
{
NSString *pathDataStr = [[NSBundle mainBundle] pathForResource:@"China" ofType:@"plist"];
NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:pathDataStr];
// 取出省份
// 先取到每個省最外層的 key
for (NSString *item in [dic allKeys])
{
//NSLog(@"①--itme--->%@", item);
// 遍歷取到 省份名
for (NSString *provinceName in dic[item])
{
// 創(chuàng)建 省份 的實(shí)體 Model
province_Model *modelP = [province_Model new];
modelP.provinceName = provinceName;
for (NSString *itemCity in dic[item][provinceName])
{
// 遍歷取到 對應(yīng)省份的 城市
for (NSString *cityName in dic[item][provinceName][itemCity])
{
city_Model *modelC = [city_Model new];
modelC.cityName = cityName;
// 依次找到 城市 對應(yīng)的縣城
modelC.countyArray = dic[item][provinceName][itemCity][cityName];
// 把對應(yīng)的城市 Model 添加到 省的城市數(shù)組中
[modelP.cityArray addObject:modelC];
}
}
[self.allProvinceArray addObject:modelP];
}
}
}
先來實(shí)現(xiàn) 日期的輸入
#pragma mark ------>> 使用鍵盤的代理方法對輸入進(jìn)行控制 監(jiān)聽的效果 <<------
// 這里返回 NO 就是不讓鍵盤輸入 而是按照我們需要的作為 textFile 的 text
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSLog(@"方法名--->%s", __func__);
return NO;
}
#pragma mark 開始編輯的時候就把默認(rèn)的 日期 和地址 顯示上 可以直接調(diào)用方法
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(@"方法名--->%s", __func__);
if (textField == self.addressFiled)
{// 調(diào)用 PickView 的選中方法 給地址 textFile 賦值 (這個方法在后面有)
[self pickerView:self.addressKB didSelectRow:0 inComponent:0];
}else
{// 調(diào)用監(jiān)聽的方法 給時間的 textFile 賦值
[self rollAction:_dateKB];
}
}
#pragma mark ------>> 監(jiān)聽滾動的方法 滾動日期鍵盤時候走的方法<<------
- (void)rollAction:(UIDatePicker *)sender
{
// 格式化日期格式
NSDateFormatter *formatter = [NSDateFormatter new];
// 設(shè)置顯示的格式 這里的格式 2016 / 08 / 08
[formatter setDateFormat:@"YYYY / MM / dd"];
// UIDatePicker 滾動也就是日期改變 我們就改變對應(yīng)的 textFile 的 text
self.timeField.text = [formatter stringFromDate:sender.date];
}
下面是實(shí)現(xiàn) 地址的輸入一些方法 先把 UIPickerView 的代理方法完成
#pragma mark ------>> UIPickView 的協(xié)議方法 編輯鍵盤 <<------
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
NSLog(@"返回列數(shù)!");
return 3;
}
#pragma mark ------>> 每個組件的 row 數(shù)量 <<------
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
// 先找到選中的省份
NSInteger indexP = self.provinceCurrentIndex;
province_Model *modelP = self.allProvinceArray[indexP];
switch (component) {
case 0:
return self.allProvinceArray.count;
break;
case 1:
{// 根據(jù)第 0 列選中省 得到對應(yīng)的城市數(shù)組
return modelP.cityArray.count;
}
break;
case 2:
{// 根據(jù)第 1 列選中城市 找到縣級的數(shù)組
city_Model *modelC = modelP.cityArray[_cityCurrentIndex];
return modelC.countyArray.count;
}
break;
default:
return 0;
break;
}
}
#pragma mark ------>> 當(dāng)我們滑動列選中某一個 row 的時候 要更新視圖 讓與之相關(guān)的列更新 <<------
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSLog(@"滾動了第 %ld 列 ",component);
switch (component) {
case 0:
// 滑動了第 0 列 更新后兩列
self.provinceCurrentIndex = [pickerView selectedRowInComponent:0];
[pickerView reloadComponent:1];
[pickerView selectRow:0 inComponent:1 animated:YES];
self.cityCurrentIndex = 0;
[pickerView reloadComponent:2];
[pickerView selectRow:0 inComponent:2 animated:YES];
break;
case 1:
// 滑動了第 1 列 更新最后一列
self.cityCurrentIndex = [pickerView selectedRowInComponent:1];
[pickerView reloadComponent:2];
[pickerView selectRow:0 inComponent:2 animated:YES];
self.countyCurrenIndex = 0;
break;
case 2:
self.countyCurrenIndex = [pickerView selectedRowInComponent:2];
break;
default:
break;
}
// 當(dāng)前選中的 省份
province_Model *modelP = self.allProvinceArray[_provinceCurrentIndex];
// 當(dāng)前的選中的 城市
city_Model *modelC = modelP.cityArray[_cityCurrentIndex];
// 當(dāng)前選中 縣城
NSString *countyStr = [NSString new];
if (_countyCurrenIndex >= modelC.countyArray.count)
{
countyStr = modelC.countyArray[0];
[pickerView selectRow:0 inComponent:2 animated:YES];
}else
{
countyStr = modelC.countyArray[_countyCurrenIndex];
}
// 給 addressFiled 賦值
self.addressFiled.text = [NSString stringWithFormat:@"%@ %@ %@",modelP.provinceName, modelC.cityName, countyStr];
}
#pragma mark ------>> PickerView 顯示的內(nèi)容 <<------
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
// 獲取第 0 列選中的省份 那么后面的城市就是這個省份的城市數(shù)組里面的
NSInteger indexP = self.provinceCurrentIndex;
province_Model *modelP = self.allProvinceArray[indexP];
// 創(chuàng)建 UILabel 用于顯示每一個 row 上面的內(nèi)容
UILabel *label = [UILabel new];
label.adjustsFontSizeToFitWidth = YES;
switch (component) {
case 0:
{// 第 0 列 顯示省份
label.text = [self.allProvinceArray[row] provinceName];
}
break;
case 1:
{// 根據(jù)第 0 選中的省份 來確定第 1 列顯示城市
label.text = [modelP.cityArray[row] cityName];
}
break;
case 2:
{// 根據(jù)第 1 列選中城市 找到縣級的數(shù)組 返回對應(yīng)的下標(biāo)的縣名
// NSInteger indexCity = [pickerView selectedRowInComponent:1];
label.text = [modelP.cityArray[_cityCurrentIndex] countyArray][row];
}
break;
default:
label.text = @"其他";
break;
}
return label;
}```