标签:
效果图:两个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
UIPickerView和UIDatePicker的简单应用(双级联动防止崩溃)
标签:
原文地址:http://www.cnblogs.com/bdlfbj/p/5537750.html