天天看點

IOS UIPickerView選擇器的使用

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
           

效果截圖:

IOS UIPickerView選擇器的使用