UIPickerView
1. UIPickerView的常見屬性
- 數據源(用來告訴UIPickerView有多少列多少行)
@property(nonatomic,assign) id<UIPickerViewDataSource> dataSource;
- 代理(用來告訴UIPickerView每1列的每1行顯示什麼內容,監聽UIPickerView的選擇)
@property(nonatomic,assign) id<UIPickerViewDelegate> delegate;
- 是否要顯示選中的指示器
@property(nonatomic) BOOL showsSelectionIndicator;
- 一共有多少列
@property(nonatomic,readonly) NSInteger numberOfComponents;
2. UIPickerView的常見方法
- 重新刷新所有列
- (void)reloadAllComponents;
- 重新刷新第component列
- (void)reloadComponent:(NSInteger)component;
- 獲得第component列的當前選中的行號
- (NSInteger)selectedRowInComponent:(NSInteger)component;
- 自動選中第component列的第row行
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated;
3. 數據源方法(UIPickerViewDataSource)
- 一共有多少列
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
- 第component列一共有多少行
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
4. 代理方法(UIPickerViewDelegate)
- 第component列的寬度是多少
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component;
- 第component列的行高是多少
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component;
- 第component列第row行顯示什麼文字
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
- 第component列第row行顯示怎樣的view(內容)
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view;
- 選中了pickerView的第component列第row行
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
5. 注意
方法 1.- (void) selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated;
方法 2.-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
注意:這兩個方法非常容易弄混,這裏重點說一下
1. 方法 1 是UIPickerView自身的方法; 方法 2 是UIPickerView代理的方法
2. 方法 2 是選中了pickerView的第component列第row行,只有人選中了PickerView,纔會自動調用,但我們可以在程序中實現主動加載,即人不選中PickerView,我們可以用代碼主動加載。
3. 方法 1 是自動選中第component列的第row行,UIPickerView會自動跳轉到component列row行。跳轉以後不會自動執行方法 2 。這點要特別注意。
效果展示
隨機點菜系統
結構
代碼
// ViewController.m
#import "ViewController.h"
@interface ViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
@property (strong, nonatomic) NSArray *food;
@property (weak, nonatomic) IBOutlet UILabel *fruitLabel;
@property (weak, nonatomic) IBOutlet UILabel *mainLabel;
@property (weak, nonatomic) IBOutlet UILabel *drinkLabel;
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
- (IBAction)randomMenu;
@end
@implementation ViewController
- (NSArray *)food{
if(_food == nil){
NSString *path = [[NSBundle mainBundle] pathForResource:@"foods.plist" ofType:nil];
_food = [NSArray arrayWithContentsOfFile:path];
}
return _food;
}
- (void)viewDidLoad {
[super viewDidLoad];
// self.fruitLabel.text = self.food[0][0];
// self.mainLabel.text = self.food[1][0];
// self.drinkLabel.text = self.food[2][0];
// 初始化
// 默認選中數據,第一行數據
for (int i = 0; i < self.food.count; ++i) {
[self pickerView:nil didSelectRow:0 inComponent:i];
}
}
- (BOOL)prefersStatusBarHidden{
return YES;
}
/**
* 一共有多少列
*/
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return self.food.count;
}
/**
* 第component列顯示多少行
*/
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return [self.food[component] count];
}
/**
* 第component列的第row行顯示什麼文字
*/
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return self.food[component][row];
}
/**
* 選中了第component列的第row行(只有人選中了PickerView,纔會自動調用,但我們可以在程序中實在主動加載,即人不選中PickerView,我們可以用代碼主動加載)
*/
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if (component == 0) { // 水果
self.fruitLabel.text = self.food[component][row];
} else if (component == 1) { // 主菜
self.mainLabel.text = self.food[component][row];
} else if (component == 2) { // 飲料
self.drinkLabel.text = self.food[component][row];
}
}
/**
* 隨機選擇菜單
*/
- (IBAction)randomMenu{
for (int i = 0; i < self.food.count; ++i) {
// 獲取每列有多少行
NSInteger num = [self.food[i] count];
// 在行範圍產生隨機數據,做爲新的行號
NSInteger randomRow = arc4random() % num;
// 獲取舊的行號
NSInteger oldRow = [self.pickerView selectedRowInComponent:i];
while (oldRow == randomRow) {
randomRow = arc4random() % num;
}
#warning 要自動改變PIckerview選中的行,要使用pickerview的一個方法
// 更改UIPickerView選中的數據
// 自動選中第component列的第row行,UIPickerView會自動跳轉到component列,row行。
[self.pickerView selectRow:randomRow inComponent:i animated:YES];
// 更改label的數據(主動加載)
[self pickerView:nil didSelectRow:randomRow inComponent:i];
}
}
@end
效果展示
省市聯動
結構
代碼
// ViewController.m
#import "ViewController.h"
#import "Province.h"
@interface ViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
@property (strong, nonatomic) NSArray *provinces;
/**
* 當前默認選中的省份
*/
@property (nonatomic, assign) NSInteger indexOfProvince;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (BOOL)prefersStatusBarHidden{
return YES;
}
/**
* 數據懶加載
*/
- (NSArray *)provinces{
if(_provinces == nil){
NSString *path = [[NSBundle mainBundle] pathForResource:@"provinces.plist" ofType:nil];
NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *provinceArray = [NSMutableArray array];
for(NSDictionary *dict in dictArray) {
Province *province = [Province provinceWithDict:dict];
[provinceArray addObject:province];
}
_provinces = provinceArray;
}
return _provinces;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 2;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
if(component == 0)
return self.provinces.count;
Province *provice = self.provinces[self.indexOfProvince];
return provice.cities.count;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
if(component == 0){
//對應列行的省份
Province *provice = self.provinces[row];
return provice.name;
}
//獲取選中的城市,顯示城市名字
Province *selectedProvice = self.provinces[self.indexOfProvince];
return selectedProvice.cities[row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if(component == 0){
self.indexOfProvince = row;
//全部刷新
//[pickerView reloadAllComponents];
//部份刷新
[pickerView reloadComponent:1];
//不管之前第二列選中第幾行,重新刷新數據後,都自動跳轉到每二列的第一行
[pickerView selectRow:0 inComponent:1 animated:YES];
}
}
@end
// Province.h
#import <Foundation/Foundation.h>
@interface Province : NSObject
@property (copy, nonatomic) NSString *name;
@property (strong, nonatomic) NSArray *cities;
+ (instancetype)provinceWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
// Province.m
#import "Province.h"
@implementation Province
+ (instancetype)provinceWithDict:(NSDictionary *)dict{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict{
if(self = [super init]){
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end
效果展示
選擇國旗
結構
代碼
// ViewController.m
#import "ViewController.h"
#import "FlagView.h"
#import "Flag.h"
@interface ViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
@property (strong, nonatomic) NSArray *flags;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (BOOL)prefersStatusBarHidden{
return YES;
}
- (NSArray *)flags{
if(_flags == nil){
NSString *path = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *flagArray = [NSMutableArray array];
for(NSDictionary *dict in dictArray){
Flag *flag = [Flag flagWithDict:dict];
[flagArray addObject:flag];
}
_flags = flagArray;
}
return _flags;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return self.flags.count;
}
#pragma mark 自定義Pickerview的行
#warning UIPikcerView循環引用在ios7以後,不太明顯,但是確實還是會循環引用,在ios6,view的循環引用是非常明顯
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
//如果有重用的view,會傳一個view進來
FlagView *flagView = (FlagView *)view;
if(flagView == nil){
flagView = [FlagView flagView];
}
flagView.flag = self.flags[row];
NSLog(@"-----view = %p, flagView = %p", view, flagView);
return flagView;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
return [FlagView flagViewHeight];
}
@end
// FlagView.h
#import <UIKit/UIKit.h>
@class Flag;
@interface FlagView : UIView
+ (instancetype)flagView;
+ (CGFloat)flagViewHeight;
@property (strong, nonatomic) Flag *flag;
@end
// FlagView.m
#import "FlagView.h"
#import "Flag.h"
@interface FlagView()
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *nameView;
@end
@implementation FlagView
+ (instancetype)flagView{
return [[[NSBundle mainBundle] loadNibNamed:@"FlagView" owner:nil options:nil] lastObject];
}
- (void)setFlag:(Flag *)flag{
_flag = flag;
self.iconView.image = [UIImage imageNamed:flag.icon];
self.nameView.text = flag.name;
}
+ (CGFloat)flagViewHeight{
return 50;
}
@end
// flag.h
#import <Foundation/Foundation.h>
@interface Flag : NSObject
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *icon;
+ (instancetype)flagWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
// flag.m
#import "Flag.h"
@implementation Flag
+ (instancetype)flagWithDict:(NSDictionary *)dict{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict{
if(self = [super init]){
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end