UIPickerView的基本概念
它是一个列选择器,可以设置列数和每一列的行数,然后通过调用它的代理方法设置每一个部分的尺寸参数和内容参数。并且可以设置它被选择后的触发效果。
源码分析
成员变量:
//此处有两个可选择的协议,实现协议后可以调用相应的代理方法
@protocol UIPickerViewDataSource, UIPickerViewDelegate;
//继承自uiview
NS_CLASS_AVAILABLE_IOS(2_0) __TVOS_PROHIBITED @interface UIPickerView : UIView <NSCoding>
//数据源代理
@property(nullable,nonatomic,weak) id<UIPickerViewDataSource> dataSource; // default is nil. weak reference
//代理
@property(nullable,nonatomic,weak) id<UIPickerViewDelegate> delegate; // default is nil. weak reference
//显示选中框(设置与否区别不大)
@property(nonatomic) BOOL showsSelectionIndicator; // default is NO
// info that was fetched and cached from the data source and delegate
//组件数,也就是列数
@property(nonatomic,readonly) NSInteger numberOfComponents;
成员方法:
//这两个方法用于设置行数和行尺寸
- (NSInteger)numberOfRowsInComponent:(NSInteger)component;
- (CGSize)rowSizeForComponent:(NSInteger)component;
// returns the view provided by the delegate via pickerView:viewForRow:forComponent:reusingView:
// or nil if the row/component is not visible or the delegate does not implement
// pickerView:viewForRow:forComponent:reusingView:
//获取指定行列对应的视图,默认返回的是nil
- (nullable UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component;
// Reloading whole view or single component
//重载组件(数据)
- (void)reloadAllComponents;
//指定组件重载
- (void)reloadComponent:(NSInteger)component;
// selection. in this case, it means showing the appropriate row in the middle
//某个行列被选中
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated; // scrolls the specified row to center.
//某个组件被选中的行数
- (NSInteger)selectedRowInComponent:(NSInteger)component;
协议方法:
此协议内容必须被实现:
@protocol UIPickerViewDataSource<NSObject>
@required
// returns the number of 'columns' to display.
//设置列数
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
// returns the # of rows in each component..
//设置行数
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
@end
此协议内容选择性实现:
@protocol UIPickerViewDelegate<NSObject>
@optional
// returns width of column and height of row for each component.
//设置宽高
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component __TVOS_PROHIBITED;
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component __TVOS_PROHIBITED;
// these methods return either a plain NSString, a NSAttributedString, or a view (e.g UILabel) to display the row for the component.
// for the view versions, we cache any hidden and thus unused views and pass them back for reuse.
// If you return back a different object, the old one will be released. the view will be centered in the row rect
//根据行列设置内容
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component __TVOS_PROHIBITED;
//富文本
- (nullable NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED; // attributed title is favored if both methods are implemented
//复用一个view实现不同内容
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view __TVOS_PROHIBITED;
//某行列被选中后触发
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component __TVOS_PROHIBITED;
@end
对代理的理解:
通过以上方法,我们可以发现,在iOS中很多参数的配置都是通过实现回调方法,也就是说,iOS为你提供了一系列API,实现他们,系统自己会去管理和实现回调,我们要做的是实现它的内容,而不用去考虑太多背后的复杂的逻辑。其中许多方法都是选择性地实现的,如果全部实现反而可能会有冲突,比如上方关于文本的两个方法,是有优先调用的。
我的实现
实现了一个日期选择器。选中后会显示被选中处的背景颜色。
头文件:
#import <UIKit/UIKit.h>
//遵守协议
@interface ViewController : UIViewController<UIPickerViewDataSource,UIPickerViewDelegate>
@property (strong , nonatomic) NSArray *years;
@property (strong , nonatomic) NSArray *months;
@property (strong , nonatomic) NSArray *days;
@end
实现部分:
#import "ViewController.h"
@interface ViewController ()
{
}
@property (nonatomic ,strong) UIPickerView *pickView;
@end
@implementation ViewController
//加载后初始化
- (void)viewDidLoad
{
[super viewDidLoad];
//配置数据
NSMutableArray *multYears = [NSMutableArray array];
for(int i=0;i<20;i++){
NSString *year = [NSString stringWithFormat:@"20%02d年",i+1];
[multYears addObject:year];
}
self.years = multYears;
NSMutableArray *multMonths = [NSMutableArray arrayWithCapacity:12];
for(int i=1;i<=12;i++){
NSString *month = [NSString stringWithFormat:@"%d月",i];
[multMonths addObject:month];
}
self.months = multMonths;
NSMutableArray *multDays = [NSMutableArray arrayWithCapacity:31];
for(int i=1;i<=31;i++){
NSString *day = [NSString stringWithFormat:@"%d日",i];
[multDays addObject:day];
}
self.days = multDays;
//实例化并设置代理
self.pickView = [[UIPickerView alloc] initWithFrame:self.view.frame];
self.pickView.dataSource = self;
self.pickView.delegate = self;
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.pickView];
}
#pragma mark - pickerView的代理方法
//设置数据源
//必须实现
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 3;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
NSInteger row = 0;
switch (component) {
case 0:
row = self.years.count;
break;
case 1:
row = self.months.count;
break;
case 2:
row = self.days.count;
break;
}
return row;
}
//获取内容的方法
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *title;
switch (component) {
case 0:
title = self.years[row];
break;
case 1:
title = self.months[row];
break;
case 2:
title = self.days[row];
break;
}
return title;
}
//被选中后调用
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSString *strDate = [NSString stringWithFormat:@"%@-%@-%@",
self.years[[pickerView selectedRowInComponent:0]],
self.months[[pickerView selectedRowInComponent:1]],
self.days[[pickerView selectedRowInComponent:2]]];
NSLog(@"%@",strDate);
//设置颜色
UIView *selectedView = [pickerView viewForRow:row forComponent:component];
switch (component) {
case 0:
selectedView.backgroundColor = [UIColor redColor];
break;
case 1:
selectedView.backgroundColor = [UIColor greenColor];
break;
case 2:
selectedView.backgroundColor = [UIColor blueColor];
break;
default:
break;
}
}
//宽度设置
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
return self.view.frame.size.width/3.0;
}
//高度设置
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
return 26;
}
//复用view
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel *label = (UILabel *)view;
if(!label) {
label = [[UILabel alloc] init];
label.contentMode = UIViewContentModeCenter;
label.textColor = [UIColor blackColor];
label.textAlignment = NSTextAlignmentCenter;
}
label.text = [self pickerView:pickerView titleForRow:row forComponent:component];
return label;
}
@end
效果截图: