天天看点

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选择器的使用