iOS-UIPickerView 詳解總結(jié)

寫在文前

由于最近開發(fā)中經(jīng)常碰到類似日期選擇器相關(guān)業(yè)務(wù)使用場(chǎng)景,雖然這個(gè)系統(tǒng)控件相對(duì)來說非常簡(jiǎn)單,有點(diǎn)兒類似UITableView的感覺,初始化之后設(shè)置數(shù)據(jù)源,代理,完成相應(yīng)的數(shù)據(jù)源方法就可以正常展示了,而且其數(shù)據(jù)源 代理方法相對(duì)來說也很少,肯花心思去思考 記憶,很快就能掌握這個(gè)控件。

一、UIPickerView 簡(jiǎn)介

UIPickerView 是一種使用旋轉(zhuǎn)輪或一個(gè)槽機(jī)映像來顯示一列或多列,可多行展示的滾動(dòng)視圖。 其與UIDatePicker 展示效果極為相似, 但是其是一個(gè)相對(duì)開發(fā)者來說更為通用的滾動(dòng)選擇器。 由類名就可以得出UIDatePicker 是為日期選擇而生, 而其是一個(gè)通用適合自定義視圖展示的選擇器。
UIPickerView 繼承自 UIView。 UIDatePicker繼承自Control。
兩者不同的父類也直接導(dǎo)致了 UIPickerView 相對(duì) UIDatePicker 也缺少了很多 Control 自帶的特性。畢竟 Control是從 UIView 繼承出來的。


UIPickerView

二、UIPickerView 相應(yīng)屬性與方法

在此我以系統(tǒng)聲明的 UIPickerView.h 文件聲明的屬性及方法依次介紹, 其實(shí)文檔上已經(jīng)寫的挺清楚了,但是在使用的時(shí)候可能也會(huì)由于理解錯(cuò)誤,介紹不夠詳細(xì)等導(dǎo)致踩坑,所以我會(huì)按系統(tǒng)文檔加上自己在使用過程中的理解心得結(jié)合起來介紹。

為了便于觀看直接把系統(tǒng) UIPickerView.h 文件代碼 Copy 過來。 直接在屬性原有注釋上添加自己的理解介紹。
//
//  UIPickerView.h
//  UIKit
//
//  Copyright (c) 2006-2017 Apple Inc. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <UIKit/UIView.h>
#import <UIKit/UIKitDefines.h>

NS_ASSUME_NONNULL_BEGIN

@protocol UIPickerViewDataSource, UIPickerViewDelegate;

NS_CLASS_AVAILABLE_IOS(2_0) __TVOS_PROHIBITED @interface UIPickerView : UIView <NSCoding>

@property(nullable,nonatomic,weak) id<UIPickerViewDataSource> dataSource; // default is nil. weak reference  數(shù)據(jù)源初始化的時(shí)候可以直接設(shè)置。
@property(nullable,nonatomic,weak) id<UIPickerViewDelegate>   delegate; // default is nil. weak reference  委托初始化的時(shí)候可以直接設(shè)置。
@property(nonatomic)        BOOL    showsSelectionIndicator;   // default is NO    
很遺憾,這個(gè)屬性在 iOS7 以及更高的系統(tǒng)就無法使用了,Apple 文檔里面有詳細(xì)介紹。   
查了下資料解釋說其顯示的效果就是在當(dāng)前選擇的行中 有一個(gè)默認(rèn)背景顏色填充的藍(lán)條。
光看著描述,不能看到效果有點(diǎn)難受QAQ, 直接Google 這個(gè)屬性找到不少相關(guān)圖片,嘿嘿嘿。

效果: 雖然系統(tǒng)屏蔽掉了這個(gè)直接設(shè)置已選列表指示器的接口。不過我們通過現(xiàn)有的公共方法實(shí)現(xiàn)起來也非常簡(jiǎn)單,直接在代理的已選中當(dāng)前 Row 中通過返回當(dāng)前 Row 的View 方法,直接設(shè)置背景即可。

UIPickerView.showsSelecttionIndicator = Yes

showsSelectionIndicator 實(shí)現(xiàn)代碼:

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{ 
      UIView* selectView = [pickerView viewForRow:row forComponent:component];
      selectView.backgroundColor = [UIColor redColor];
}
// info that was fetched and cached from the data source and delegate
// Getting the Dimensions of the View Picker
// 這三個(gè)方法可以直接獲取到當(dāng)前 UIPickerView 行數(shù),列數(shù),每列的展示行相應(yīng)大小數(shù)據(jù)。
@property(nonatomic,readonly) NSInteger numberOfComponents;   // 可直接獲取當(dāng)前選擇器的列個(gè)數(shù)。
- (NSInteger)numberOfRowsInComponent:(NSInteger)component;   //  參數(shù)代表當(dāng)前列下標(biāo)。直接返回當(dāng)前列總共包含多少行組件。
- (CGSize)rowSizeForComponent:(NSInteger)component;  //   參入指定列下標(biāo),返回當(dāng)前所展示單行視圖的寬度和高度。

// 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:
- (nullable UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component;
// 此方法是傳入指定行和列 返回其表示的 View 視圖。  但是要主要這個(gè)方法是通過 代理方法此 pickerView:viewForRow:forComponent:reusingView:
// 獲取到的 View。  所以如果我們沒有實(shí)現(xiàn)此代理方法的話,調(diào)用則返回 nil。
// Reloading whole view or single component
- (void)reloadAllComponents;      // 刷新整個(gè)選擇控制器。 類似 UITableView 里的 - (void)reloadData;
- (void)reloadComponent:(NSInteger)component; // 傳入列下標(biāo),指定刷新這一列數(shù)據(jù)。

// 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.
// 傳入行和列下標(biāo),選擇控制器會(huì)滾動(dòng)到相應(yīng)視圖, 并使其展示在中間。

- (NSInteger)selectedRowInComponent:(NSInteger)component;                                   // returns selected row. -1 if nothing selected
//  傳入當(dāng)前列下標(biāo),返回當(dāng)前選擇控制器當(dāng)前所選中的 Row 下標(biāo)。

@end

數(shù)據(jù)源

//只有兩個(gè)必須實(shí)現(xiàn)的方法。
__TVOS_PROHIBITED
@protocol UIPickerViewDataSource<NSObject>
@required

// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView; //參數(shù)表示當(dāng)前 pickerView,返回選擇器總共有幾列。

// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
//參數(shù) pickerView 表示當(dāng)前 pickerView 視圖,component 表示所在列下標(biāo), 返回指定列下標(biāo)的行數(shù)。
@end

代理

// 6個(gè)方法都是非常好理解的。

__TVOS_PROHIBITED
@protocol UIPickerViewDelegate<NSObject>
@optional

// returns width of column and height of row for each component. 
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component 
//   傳入當(dāng)前列下標(biāo),返回值為此行的寬度。 可以通過這個(gè)方法來單獨(dú)設(shè)置每一列的寬度。
__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  
// 這三個(gè)方法都是決定 UIPickerVier 展示的內(nèi)容,效果。  如果對(duì)視圖沒有定義要求的話,直接使用前面兩個(gè)即可。 
// 第三個(gè)方法是可以自定義視圖進(jìn)行展示的,并且其原理也是類似UITableView一樣用復(fù)用的功能。
// 細(xì)節(jié):這三個(gè)方法 第一個(gè) 和 第二個(gè) 如果我們同時(shí) 實(shí)現(xiàn)了,則系統(tǒng)會(huì)先調(diào)用返回 NSAttributedString 的方法,其次在去調(diào)用 返回 NSString 的方法。  
// 但是如果我們實(shí)現(xiàn)了 返回 UIView 的方法的話, 其他兩個(gè)方法均不會(huì)在被調(diào)用。 這點(diǎn)要注意一下。
- (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
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view __TVOS_PROHIBITED;

//  這個(gè)方法顧名思義,在用戶滑動(dòng) 選擇器列表的時(shí)候會(huì)調(diào)用此方法。  類似UITableView里面的 將要選擇那一分區(qū)里面那一行一樣的!
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component __TVOS_PROHIBITED;

@end

NS_ASSUME_NONNULL_END

到這里已經(jīng)基本把 UIPickerView 相關(guān)的所有屬性及方法介紹完畢。 相信沒有使用過這個(gè)控件的朋友基本也差不多明白是怎么回事了。
這里我再附上簡(jiǎn)單的代碼實(shí)現(xiàn)來供大家參考。

// pickView初始化并設(shè)置其大小,如果不設(shè)置其大小,默認(rèn)大小為 320 * 216。
- (void)viewDidLoad {
 [super viewDidLoad];

 UIPickerView* pickerView = [[UIPickerView alloc] initWithFrame:self.view.frame];
 pickerView.delegate = self;
 pickerView.dataSource = self;
 [self.view addSubview:pickerView];
}


#pragma mark - UIPickerView DataSource and Delegate 

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
 return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
 return self.dataSource.count;
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
 return 46;
}

- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return @"JerseyCocoa";
}

效果如圖:

Show-UIPickerView
也可以通過另外兩個(gè)代理方法來實(shí)現(xiàn) UIPickerView 的展示。 我一般比較喜歡用復(fù)用 View 的方法。不僅能節(jié)省內(nèi)存開銷,自定義修改視圖字體等都很輕松的實(shí)現(xiàn)。
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
    UILabel* pickerLabel = (UILabel*)view;
    if (!pickerLabel) {
        pickerLabel = [[UILabel alloc] init];
        pickerLabel.font = [UIFont systemFontOfSize:15];
        pickerLabel.contentMode = UIViewContentModeCenter;
        pickerLabel.textColor = [UIColor blueColor];
    }
    pickerLabel.text = [self pickerView:pickerView titleForRow:row forComponent:component];
    return pickerLabel;
}
如果我們使用這種方法來實(shí)現(xiàn) UIPickerView 的展現(xiàn)的話,還有一個(gè)好處就是可以通過 調(diào)用 UIPickerView 的
 - (nullable UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component; 
方法就能輕松實(shí)現(xiàn) 其 iOS 7 以后就隱藏掉的屬性  showsSelectionIndicator。
具體實(shí)現(xiàn)如下:
在實(shí)現(xiàn)了上面的復(fù)用自定義視圖代理方法基礎(chǔ)上,調(diào)用選擇指定行列下標(biāo)代理方法。
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    UIView* view = [self pickerView:pickerView viewForRow:row forComponent:component reusingView:nil];
    view.backgroundColor = [UIColor greenColor];
}
效果如圖:
pickerView.showsSelectionIndicator = Yes

到這里 UIPickerView 的介紹基本結(jié)束了,想必閱讀下來大家肯定都能動(dòng)手自己寫一個(gè)適合自己業(yè)務(wù)場(chǎng)景使用的 UIPickerView了。

補(bǔ)充個(gè)實(shí)用的Tips

一、UIPickerView 默認(rèn)是會(huì)顯示在中心的 視圖上下分割線, 有時(shí)候我們想去去掉這條分割線,或者改變顏色可以使用這個(gè)方法。

    //清除或改變分割線的顏色等。
    for(UIView *singleLine in _pickerView.subviews)
    {
        if (singleLine.frame.size.height < 1)
        {
            singleLine.backgroundColor = [UIColor clearColor];
            [singleLine removeFromSuperview];
        }
    }

最后

本文參考了很多前輩的文章及開發(fā)中自己總結(jié)的結(jié)論,希望此篇文章對(duì)您有所幫助,如有不對(duì)的地方,希望大家能留言指出糾正。歡迎大家一起交流學(xué)習(xí) 澤西島上咖啡?。。。?!

學(xué)習(xí)的路上, 與君共勉!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容