We don’t add UIPickerView as subview. There is a trick to achieve this.

Create a dummy UITextField

This text field is not visible to user, is a hidden field

ViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) UITextField *pickerViewTextField;

@end

@implementation ViewController

@synthesize pickerViewTextField = _pickerViewTextField;

- (void)viewDidLoad
{
[super viewDidLoad];

// set the frame to zero
self.pickerViewTextField = [[UITextField alloc] initWithFrame:CGRectZero];
[self.view addSubview:self.pickerViewTextField];

UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;

// set change the inputView (default is keyboard) to UIPickerView
self.pickerViewTextField.inputView = pickerView;

// add a toolbar with Cancel & Done button
UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
toolBar.barStyle = UIBarStyleBlackOpaque;

UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneTouched:)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelTouched:)];

// the middle button is to make the Done button align to right
[toolBar setItems:[NSArray arrayWithObjects:cancelButton, [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], doneButton, nil]];
self.pickerViewTextField.inputAccessoryView = toolBar;

...
}

Trigger the picker view when click on UIButton

ViewController.m

1
2
3
4
5
...
- (IBAction)someButtonTouched:(UIButton *)sender
{
[self.pickerViewTextField becomeFirstResponder];
}

Add methods for bar buttons

ViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)cancelTouched:(UIBarButtonItem *)sender
{
// hide the picker view
[self.pickerViewTextField resignFirstResponder];
}

- (void)doneTouched:(UIBarButtonItem *)sender
{
// hide the picker view
[self.pickerViewTextField resignFirstResponder];

// perform some action
}

Add dataSource & delegate for UIPickerView

ViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma mark - UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [yourItems count];
}

#pragma mark - UIPickerViewDelegate
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *item = [yourItems objectAtIndex:row];

return item;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// perform some action
}

Don’t forget to make your ViewController conform to the protocols

ViewController.h

1
@interface ViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>

You’re done :)