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
效果截圖: