1. UIPickerView 什么时候使用?
通常在注册模块,当用户需要选择一些东西的时候使用,比如说城市,往往弹出一个 PickerView 给用户选择。
2. UIPickerView 常见用法
(1)独立的,没有任何关系 —>菜单系统;
(2)相关联的,下一列和第一了有联系 —>省会城市选择;
(3)图文并茂,—>国旗选择。
3. UIPickerView 数据源方法和代理方法简述
首先进入 UIPickerView 控件描述,发现其有 dataSource 和 delegate 。
为了监听控件发生的行为,我们需要对控件设置代理,而UIPickerView不仅要设置代理,也要设置数据源。是因为之后要通过数据来确定 UIPickerView 有多少行,多少列。
代理,其实就是众多方法声明的集合,那么这么多的方法。设置完代理,还需遵守代理协议,实现代理方法。
实现协议方法
数据源协议中有必须要实现的两个方法,需要去实现,不然会报错。代理协议中没有必须要实现的方法,有一些可选的实现方法。
两个必须实现的方法简述:
// returns the number of 'columns' to display.
// 返回有多少列(即,有几个picker)
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 3;
}
// returns the # of rows in each component..
// 返回第component列有多少行
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return 5;
}
代理协议中的可选方法简述:
可选方法较多,这里不一一解释,下面对其中几个比较重要的方法进行说明。
// 返回第 component 列第 row 行的标题
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (component == 1 && row == 1) {
return @"BCD";
}
return @"ABC";
}
// NSAttributedString:给文本添加一些属性,富文本,设置文本颜色,字体,空心,阴影,图文混排等
- (nullable NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component
{
}
// 返回第 component 列第 row 行的控件
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{
}
// 监听 UIPickerView 选中哪行哪列,只要一滑动UIPickerView,就会调用这个方法;
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSLog(@"%ld %ld",component,row);
}
到此,我们可以加载数据了,之前说过,数据源协议里面的方法需要用到数据来实现,所以接下来我们开始导入数据。
用懒加载的方法加载数据,这样可以避免重复导入,提高效率,如果这个数组中没有值,就进行赋值;如果里面有值,就直接返回这个数组。
加载 .plist 文件,来进行数据的导入:
注意: 这里带下划线的变量是声明的 property 后自动生成的实例变量,不包含 set 和 get 方法,也可以理解成是一种编程习惯。
将数据导入之后,改变一些方法内容,写成通用形式。
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return self.foods.count;
}
// returns the # of rows in each component..
// 返回第component列有多少行
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
NSArray *arr = self.foods[component];
return arr.count;
}
// 返回第 component 列第 row 行的标题
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSArray *arr = self.foods[component];
return arr[row];
}
// 监听 UIPickerView 选中
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSString *title = self.foods[component][row];
self.label.text = title;
}
self.xxx 与 属性用下划线的区别:
(1)通过 self.xxx 访问的方法的引用,包含了set和get方法。而通过属性下划线是获取自己的实例变量,不包含set和get的方法;
(2)self.xxx 是对属性的访问;而属性 _xxx 是对局部变量的访问,所有被声明为属性的成员;
(3)使用 self.xxx 是更好的选择,因为这样可以兼容懒加载,同时也避免了使用下滑线的时候忽略了 self 这个指针,后者容易在Block中造成循环引用。同时,使用属性下划线是获取不到父类的属性的,因为它只是对局部变量的访问。
因此,self 方法实际上是用了 get 和 set 方法间接调用,属性下划线方法是直接对变量操作。
最后,附一张自定义的 UIPickerView 实例代码和运行结果图: