UI--UIPickerView和UIDatePicker的總結,uidatepicker
回到頂部UIPickerView的主要方法和城市選取器的修正
UIPickerView只有兩個資料來源方法.要想完整地顯示出PickerView,需要結合使用代理方法 資料來源方法:
// 一共有多少組(列)- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView// 每列有多少行,傳入的參數component是對應的列- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
UIPickerView的代理方法:
// 告訴系統每一行顯示什麼資料 通常可以結合switch case使用的- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component; // 監聽pickerView的點擊事件- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
一些其他的常用方法
// pickerView的對象方法,選擇指定列的指定行- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated// 對象方法,擷取指定列的當前選擇的行的行號,如果沒有選中任何行 就會返回-1- (NSInteger)selectedRowInComponent:(NSInteger)component;
城市選擇程式中同時修改省份和城市的時候,會造成程式崩潰的原因和修改方案:
在 這個項目中最容易出問題的地方是:每次選取器在變化的過程中,注意是變化的過程中,會不斷地調用下面兩個方法
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
在這兩個方法中,若是用這個方法以下方法擷取當前被選中的項
- (NSInteger)selectedRowInComponent:
這個方法返回的的值是變化的,因此若根據這個值計算com1的選中項的索引,很容易造成數組越界。 因此我的解決方案是用成員變數這個值。每次didSelected時,也就是已經確定值之後,改變這個固定的值。
1.首先增加類的成員屬性selectedRowOfComp1
2.在計算第二列也就是"城市"列的列數的時候按照成員屬性儲存的選擇的第一行進行計算。在pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
中
if (component == 0) { return self.provinces.count;}MKProvince *p = self.provinces[self.selectedRowOfComp1];return p.cities.count;
由此每行需要顯示資料的方法中也做了改動:
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{ if (component == 0) { MKProvince *p = self.provinces[row]; return p.name; } else { MKProvince *p = self.provinces[self.selectedRowOfComp1]; return p.cities[row]; }}
3.當省份部分的資料選定之後,要修改成員屬性,並且重新整理城市部分的資料。在label中要顯示的城市和省份也是根據成員屬性值來計算的:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ if (component == 0) { MKProvince *p = self.provinces[row]; // 改變lbl的顯示 self.lblProvince.text = p.name; // 改變城市組的顯示 self.selectedRowOfComp1 = row; [pickerView reloadComponent:1]; // 這句話一定要在self.selectedRowOfComp1 = row;之後。 reloadComponent:1重新載入component1但是不會改變已經選中的行號,因此可能會造成已經選中的是第二行,對於省份變成重慶這樣的只有一個市的省份可能會引起bug,但是不會的,因為像這樣的情況reload會將城市的資料顯示為第一行 // 更新lblCity的資料 NSInteger cityIndex = [pickerView selectedRowInComponent:1]; self.lblCity.text = p.cities[cityIndex];// 上一句使得component1更新,這句保證了lbl和component1資料一致 } else { MKProvince *p = self.provinces[self.selectedRowOfComp1]; // 改變lbl的顯示 self.lblCity.text = p.cities[row]; }}
回到頂部UIDatePicker的使用,並抽取為工具類
建立一個UIDatePicker
// 先建立dataPickerCGFloat width = [UIScreen mainScreen].bounds.size.width;UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, width, 180)];datePicker.locale = [NSLocale localeWithLocaleIdentifier:@"zh-Hans"]; // 設定預設的地區datePicker.datePickerMode = UIDatePickerModeDate; // 設定輸入的模式是日期self.datePicker = datePicker; // 設定為控制器的屬性self.txtTime.inputView = self.datePicker; // 將datePicker設定為textField控制項的輸入器// DatePicker輸入器的附屬viewUIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, width, 44)];UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithTitle:@"上一個" style:UIBarButtonItemStylePlain target:self action:@selector(previous)];UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:@"下一個" style:UIBarButtonItemStylePlain target:self action:@selector(next)];UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];UIBarButtonItem *item4 = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(done)]; // 設定完成的監聽事件toolbar.items = @[item1, item2, item3, item4]; self.txtTime.inputAccessoryView = toolbar; // 將toolbar設定為textField的輸入器附屬view
處理輸入完成後done按鈕的點擊事件
- (void)done{ [self.view endEditing:YES]; // 將選擇的日期格式化 NSDate *date = self.datePicker.date; NSDateFormatter *fmt = [[NSDateFormatter alloc]init]; fmt.dateFormat = @"yyyy年MM月dd日"; NSString *dateStr = [fmt stringFromDate:date]; // 將格式化後的字串賦值給textField self.txtTime.text = dateStr; }
抽取為工具類
建立工具類MKToolDatePicker,在MKToolDatePicker.h中
#import "MKTool.h"@class UITextField;@protocol MKToolDatePickerDelegate;/** * 建立後需要強引用這個類 */@interface MKToolDatePicker : MKTool/** * 指定要設定的UITextField控制項 */@property (nonatomic, weak) id delegate;- (void)datePickerOnTextField:(UITextField *)textField;@end@protocol MKToolDatePickerDelegate /** * 當點擊了時間選取器的"完成"按鈕,並且代理類(一般為控制器)已經實現了該方法的時候調用,用於處理選擇的NSDate * * @param toolDatePicker 工具類對象本本身 * @param textField 指定的textField * @param date 點擊"完成"之前選擇的date */- (void)toolDatePicker:(MKToolDatePicker *)toolDatePicker onView:(UITextField *)textField didClickedDoneWithDate:(NSDate *)date;@end
在MKToolDatePicker.m中
#import "MKToolDatePicker.h"#import <UIKit/UIDatePicker.h>#import <UIKit/UIScreen.h>#import <UIKit/UIToolbar.h>@interface MKToolDatePicker ()@property (nonatomic, strong) UIDatePicker *datePicker;@property (nonatomic, strong) UIToolbar *toolBar;@property (nonatomic, weak) UITextField *textField;@end@implementation MKToolDatePicker- (UIDatePicker *)datePicker{ if (!_datePicker) { // 先建立dataPicker CGFloat width = [UIScreen mainScreen].bounds.size.width; _datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, width, 180)]; _datePicker.locale = [NSLocale localeWithLocaleIdentifier:@"zh-Hans"]; _datePicker.datePickerMode = UIDatePickerModeDate; } return _datePicker;}- (UIToolbar *)toolBar{ if (!_toolBar) { // 輸入的附屬view _toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)]; UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithTitle:@"上一個" style:UIBarButtonItemStylePlain target:self action:@selector(previous)]; UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:@"下一個" style:UIBarButtonItemStylePlain target:self action:@selector(next)]; UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIBarButtonItem *item4 = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(done)]; _toolBar.items = @[item1, item2, item3, item4]; } return _toolBar;}- (void)datePickerOnTextField:(UITextField *)textField{ self.textField = textField; textField.inputView = self.datePicker; textField.inputAccessoryView = self.toolBar;}- (void)done{ [self.textField endEditing:YES]; if ([self.delegate respondsToSelector:@selector(toolDatePicker:onView:didClickedDoneWithDate:)]) { [self.delegate toolDatePicker:self onView:self.textField didClickedDoneWithDate:self.datePicker.date]; } }
在控制器中使用時間選取器工具類
#import "ViewController.h"#import "MKToolDatePicker.h"@interface ViewController () @property (weak, nonatomic) IBOutlet UITextField *txtTime;// 強引用時間選取器工具@property (nonatomic, strong) MKToolDatePicker *toolDatePicker;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; MKToolDatePicker *tool = [[MKToolDatePicker alloc]init]; self.toolDatePicker = tool; tool.delegate = self; // 設定代理 [tool datePickerOnTextField:self.txtTime]; // 指定UITextView}// 根據onView的不同分別處理- (void)toolDatePicker:(MKToolDatePicker *)toolDatePicker onView:(UITextField *)textField didClickedDoneWithDate:(NSDate *)date{ NSDateFormatter *fmt = [[NSDateFormatter alloc]init]; fmt.dateFormat = @"yyyy年MM月dd日"; NSString *dateStr = [fmt stringFromDate:date]; self.txtTime.text = dateStr;}@end