UIPickerView和UIDatePicker的简单应用(双级联动防止崩溃)


效果图:两个label、两个textField、两个button(背景是图片);点击时间对应的按钮,创建选择日期的DatePicker(并移除选择地点的PickerView),选择日期,将结果传到相应textField内,点击地点对应的按钮,创建选择地点的PickerView(并移除选择地点的DatePicker),选择地点,将结果传到相应的textField内,选择地点时,同时滑动省和城市这两列,不会崩溃

直接上代码吧,里面有注释;界面使用storyBoard搭建的,

首先是viewController.m中的代码:

 1 #import "ViewController.h"
 2 #import "DataModel.h"
 3 
 4 @interface ViewController ()<UIPickerViewDataSource, UIPickerViewDelegate>
 5 ///日期输入框
 6 @property (weak, nonatomic) IBOutlet UITextField *dateField;  7 ///地点输入框
 8 @property (weak, nonatomic) IBOutlet UITextField *placeField;  9 
 10 @property (nonatomic, strong) UIPickerView *myPickerView;  11 @property (nonatomic, strong) UIDatePicker *datePicker;  12 //当省列表和城市列表同时滑动时,刷新不及时,造成数组越界,程序崩溃,该变量用于记录当前省份在provinceArray中的角标,防止崩溃
 13 @property (nonatomic, assign) NSInteger provinceIndex;  14 
 15 ///加载plist文件数据所需属性
 16 @property (nonatomic, strong) NSMutableArray *provinceArray;  17 
 18 @end
 19 
 20 @implementation ViewController  21 //懒加载读取plist文件中的数据
 22 - (NSMutableArray *)provinceArray {  23     if (_provinceArray == nil) {  24         _provinceArray = [NSMutableArray array];  25         NSString *pathString = [[NSBundle mainBundle] pathForResource:@"provinces.plist" ofType:nil];  26         NSArray *arry = [NSArray arrayWithContentsOfFile:pathString];  27         for (NSDictionary *dict in arry) {  28             DataModel *model = [[DataModel alloc] init];  29  [model setValuesForKeysWithDictionary:dict];  30  [_provinceArray addObject:model];  31  }  32 
 33  }  34     return _provinceArray;  35 }  36 
 37 - (void)viewDidLoad {  38  [super viewDidLoad];  39     // Do any additional setup after loading the view, typically from a nib.
 40     
 41 }  42 
 43 #pragma mark - 日期选择按钮的响应方法
 44 - (IBAction)dateAction:(UIButton *)sender {  45  [self.myPickerView removeFromSuperview];  46     if (self.datePicker == nil) {  47         
 48         //设置UIDatePicker;只创建一次,防止多次点击按钮,创建多个对象,占用过多内存
 49         self.datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 300, self.view.frame.size.width, 200)];  50  }  51     //设置本地时间为中国
 52     self.datePicker.locale = [NSLocale localeWithLocaleIdentifier:@"ch"];  53     //日期显示格式
 54     self.datePicker.datePickerMode = UIDatePickerModeDate;  55  [self.view addSubview:self.datePicker];  56  [self changeValue:self.datePicker];  57     //添加监听,当滑动选择的时候触发changeValue:方法
 58  [self.datePicker addTarget:self action:@selector(changeValue:) forControlEvents:UIControlEventValueChanged];  59     
 60 }  61 //监听触发方法的实现,将self.datePicker显示的日期转换成字符串显示在self.dateField上
 62 - (void)changeValue:(UIDatePicker *)datePicker {  63         NSDateFormatter *format = [[NSDateFormatter alloc] init];  64         format.dateFormat = @"yyyy-MM-dd";  65         NSString *dateString = [format stringFromDate:datePicker.date];  66     self.dateField.text = dateString;  67 }  68 #pragma mark - 地点选择按钮的响应方法
 69 - (IBAction)placeAction:(UIButton *)sender {  70     //先将self.datePicker从父视图移除,再添加self.myPickerView
 71  [self.datePicker removeFromSuperview];  72     //设置UIPickerView
 73     if (self.myPickerView == nil) {//只创建一次,防止多次点击按钮,创建多个对象,占用过多内存
 74          self.myPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 300, self.view.frame.size.width, 200)];  75  }  76  [self.view addSubview:self.myPickerView];  77     //设置代理
 78     self.myPickerView.dataSource = self;  79     self.myPickerView.delegate = self;  80     [self pickerView:self.myPickerView didSelectRow:0 inComponent:0];//给placeField赋初始值
 81     
 82 }  83 //设置列数
 84 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {  85     return 2;  86 }  87 //设置每列的行数
 88 - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {  89     if (component == 0) {  90        return self.provinceArray.count;//第一列显示各个省份
 91     }else {  92         DataModel *model = self.provinceArray[self.provinceIndex];  93        return model.cities.count;//第二列根据第一列选中的省份,显示该省的城市,
 94  }  95 }  96 //设置每行显示的内容,若不设置,默认显示的都是?
 97 - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {  98     if (component == 0) {  99         DataModel *model = self.provinceArray[row]; 100         return model.name; 101     }else { 102        // NSInteger *index = [self.myPickerView selectedRowInComponent:0] 103         //DataModel *model = self.provinceArray[index];//之所以不用该句,是因为该句获取的是当前省份的城市,当省列表和城市列表同时滑动时,刷新不及时(UI刷新之后row的范围才能改变,例如UI刷新之前row的范围是1-10,省列表和城市列表同时滑动时,使用上面两句代码,当前省份随着滚动而改变,若某个省份的城市数量小于10,后面代码“return model.cities[row];”就会数组越界,程序崩溃),造成数组越界,程序崩溃,所以在开始的时候声明一个记录当前省份的变量provinceIndex。
104         DataModel *model = self.provinceArray[self.provinceIndex]; 105         return model.cities[row]; 106  } 107 } 108 //滚动的时候,触发的方法
109 - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 110     if (component == 0) { 111         //记录当前选中的省份
112         self.provinceIndex = [self.myPickerView selectedRowInComponent:0]; 113         [self.myPickerView reloadComponent:1]; 114  } 115     DataModel *model = self.provinceArray[self.provinceIndex]; 116     NSInteger index = [self.myPickerView selectedRowInComponent:1]; 117     NSString *string = [model.name stringByAppendingString:model.cities[index]];//注意:这里model.cities[index],要获取当前列选中的行数,不能使用model.cities[row],否则会造成数组越界
118     self.placeField.text = string; 119 } 120 
121 @end

然后是DataModel.h中的代码:该部分是取出plist文件中的数据时创建的模型:

1 #import <Foundation/Foundation.h>
2 
3 @interface DataModel : NSObject 4 ///存放城市
5 @property (nonatomic, strong) NSArray *cities; 6 ///省的名称
7 @property (nonatomic, strong) NSString *name; 8 
9 @end

最后是DataModel.m中的代码

1 #import "DataModel.h"
2 
3 @implementation DataModel 4 //使用KVC赋值,防止程序崩溃
5 - (void)setValue:(id)value forUndefinedKey:(NSString *)key { 6     
7 } 8 
9 @end

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM