// 返回有多少列
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView; // 返回第component有多少行 - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
// 返回第component列多宽
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component // 返回第component列多高 - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component // 返回第component列第row行标题 - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component // NSAttributedString:富文本,可以描述文本的外观属性,颜色,字体,阴影,空心,图文混排 // - (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component // 返回第component列第row行视图控件 - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view // 当用户选中某一行的时候调用 // 选中第component列第row行的时候调用 // 可以监听pickerView滚动 - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
// 是否允许改变文本框的文字
// 是否允许用户输入文字
// 作用:拦截用户的输入
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
return NO;
}
// 是否允许开始编辑
// 允许编辑文本框
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
// 是否允许文本框结束编辑
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
自定义键盘
KVC底层实现
// setValuesForKeysWithDictionary底层实现
// 利用KVC字典转模型,
[flag setValuesForKeysWithDictionary:dict];
// 1.遍历字典中的所有key
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// 2.给模型的属性赋值,利用KVC,把字典中的key当做模型的属性名使用,字典中的值传递给模型的属性.
[flag setValue:obj forKey:key];
// name -> icon
// KeyPath:模型中的属性名
// 属性的值
// [flag setValue:dict[@"name"] forKey:@"name"];
// [flag setValue:dict[@"icon"] forKey:@"icon"];
}];
// setValue:forKey:底层实现
// 给模型中的icon属性赋值
// [flag setValue:dict[@"icon"] forKey:@"icon"];
// 1.首先去寻找模型中有木有setIcon:方法,直接调用setIcon:方法,[flag setIcon:dict[@"icon"]]
// 2.接着寻找模型中有没有icon的属性名,如果有,就直接赋值 icon = dict[@"icon"]
// 3.接着寻找模型中有没有_icon的属性名,如果有,就直接赋值 _icon = dict[@"icon"]
// 4.找不到,直接报错,setValue:forUndefinedKey:
// 创建一个UIDatePicker
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
// 设置日期模型
datePicker.datePickerMode = UIDatePickerModeDate;
// 设置地区,zh:中国
datePicker.locale = [NSLocale localeWithLocaleIdentifier:@"zh"];
// 监听UIDatePicker的选中的日期
[datePicker addTarget:self action:@selector(dateChange:) forControlEvents:UIControlEventValueChanged];
// 选中日期的时候调用
- (void)dateChange:(UIDatePicker *)datePicker
{
// 获取日期 显示到文本框上
// 日期格式字符串对象
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 设置格式 1988-01-01
fmt.dateFormat = @"yyyy-MM-dd";
self.text = [fmt stringFromDate:datePicker.date];
}
@interface Province : NSObject
@property (nonatomic, strong) NSArray *cities; /**< 省的所有城市 */
@property (nonatomic, strong) NSString *name; /**< 省会的名称 */
+ (instancetype)provinceWithDict:(NSDictionary *)dict;
@end
@implementation Province
+ (instancetype)provinceWithDict:(NSDictionary *)dict
{
Province *p = [[self alloc] init];
[p setValuesForKeysWithDictionary:dict];
return p;
}
@end
@property (nonatomic, strong) NSMutableArray *provinces;/* 保存所有省的模型 */
@property (nonatomic, assign) NSInteger proIndex; /**< 选中省会的角标 */
- (NSMutableArray *)provinces
{
if (_provinces == nil) {
_provinces = [NSMutableArray array];
// 获取到文件的全路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"provinces.plist" ofType:nil];
// 解析plist文件
NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
// 字典转模型
for (NSDictionary *dict in dictArr) {
// 创建省会模型
Province *p = [Province provinceWithDict:dict];
[_provinces addObject:p];
}
}
return _provinces;
}
// 自定义城市键盘
- (void)setUp
{
// 创建pickerView
UIPickerView *pickerView = [[UIPickerView alloc] init];
// 设置数据源
pickerView.dataSource = self;
// 设置代理
pickerView.delegate = self;
self.inputView = pickerView;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
// 0列:省,
// 1列:第0列选中的省的城市
if (component == 0) { // 描述省
return self.provinces.count;
}else{ // 描述选中省的城市
// 角标选中省的角标 => 第0列选中哪一行
// 获取选中省的模型
Province *p = self.provinces[_proIndex];
return p.cities.count;
}
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (component == 0) { // 描述省会
// 获取省
Province *p = self.provinces[row];
return p.name;
}else{ // 描述选中省的城市
// 获取当前选中的省
Province *p = self.provinces[_proIndex];
return p.cities[row];
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if (component == 0) { // 选择省
// 记录下当前选中哪个省的角标
_proIndex = row;
// 刷新城市
[pickerView reloadComponent:1];
}
// 设置文本框内容
// 获取选中省
Province *p = self.provinces[_proIndex];
NSString *proName = p.name;
// 获取选中的城市 => 第1列选中的城市
NSInteger cityIndex = [pickerView selectedRowInComponent:1];
// 获取选中城市的名称
NSString *cityName = p.cities[cityIndex];
self.text = [NSString stringWithFormat:@"%@ %@",proName,cityName];
}
注意二级联动的问题,两列同时滚动,会报角标越界错误
解决方法:当前弹出键盘的文本框是第一个角标的时 候,上一个不允许点击
// UIStoryboard : 帮你加载storyboard文件
// 加载storyboard文件
// name:storyboard文件名,不需要后缀名
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// 方法1:创建storyboard描述的控制器
// instantiateInitialViewController帮你加载箭头指向的控制器
UIViewController *vc = [storyboard instantiateInitialViewController];
// 方法2:根据标识符创建storyboard描述的控制器
// UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"org"];
// 1.创建窗口
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 2.创建窗口的根控制器
// 通过xib创建控制器,原因:是想通过Xib描述控制器的view
XMGViewController *vc = [[XMGViewController alloc] initWithNibName:@"VC" bundle:nil];
self.window.rootViewController = vc;
// 3.显示窗口
[self.window makeKeyAndVisible];
return YES;
注意:
1.只要重写loadView,必须自己手动创建控制器的view
2.在没给_view赋值之前,不能调用self.view;
// 通过xib创建XMGViewController控制器的view
1.判断下nibName有没有值,如果有值,就会去加载nibName指定的xib
2.如果nibName为空,会先去查找有没有XMGView.xib,如果有就去加载
3.如果没有XMGView.xib,就会去加载根类名同名的xib:XMGViewController.xib
4.如果还没有找到,就生成一个空的view
控制器的view延迟加载,用到时再加载
可用isViewLoaded方法判断一个UIViewController的view是否已经被加载
控制器的view加载完毕就会调用viewDidLoad方法
用一个控制器A去管理3个控制器B、C、D
iOS提供了2个比较特殊的控制器
UINavigationController的使用步骤
导航控制器的基本使用
// 1.创建窗口
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 创建一个导航控制器的根控制器
UIViewController *vc = [[OneViewController alloc] init];
// 创建导航控制器
// 导航控制器必须要有一个根控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
// 底层会调用push方法,类似下代码
// [nav pushViewController:vc animated:YES];
// initWithRootViewController底层其实是调用导航控制器的push方法,把vc成为导航控制器的子控制器
// 2.设置窗口的根控制器
self.window.rootViewController = nav;
// 3.显示窗口
[self.window makeKeyAndVisible];
return YES;
// 跳转到第二个界面
- (IBAction)jump2Two:(id)sender {
// 创建第二个控制器
TwoViewController *two = [[TwoViewController alloc] init];
// 跳转
// 如果是导航控制器的子控制器可以直接拿到导航控制器
[self.navigationController pushViewController:two animated:YES];
}