Copy-pasteable solution!
This works in iOS 10 (and probably other versions too) I wrote this code on 9/4/2017.
I needed to combine other answers to get what I wanted, which was a Cancel
button, Done
button, and a picker view that would show/hide on the tap of a button. Ignore the fact that my screenshot only has one item in the picker.. I only have one item in my array. I've tested multiple items, it works fine.

Disclaimer! I have tested and used this code. I generalized the names in my example, so I apologize in advance if I missed one and they property names don't line up.
In order to have a pickerView that appears on the tap of a button, you need to create a dummyTextField (of type UITextField
anywhere in your view controller. This is because UIPickerView
's are designed to work with UITextFields. To mimic showing and hiding of the picker, your button taps need to call the dummyTextField's becomeFirstResponder
and resignFirstResponder
methods. (examples are below)
Step one
Create a custom data source class. MyObj is the class you want to have items show up in the picker for.
In .h:
#import <UIKit/UIKit.h>
@class myObj;
@interface PickerDataSource : NSObject <UIPickerViewDataSource, UIPickerViewDelegate>
@property (nonatomic, strong) MyObj *selectedObject;
@end
In .m:
#import "PickerDataSource.h"
#import "MyObj.h"
@implementation PickerDataSource
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.selectedObject = mySourceArray[row];
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return mySourceArray.count;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return ((MyObj *)mySourceArray[row]).myTitle;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
int sectionWidth = 300;
return sectionWidth;
}
@end
Step two In your view controller, import custom data source, delegate, and set properties: (You must include the text field delegate!)
#import "PickerDataSource.h"
@interface MyViewController () <UIPickerViewDelegate, UITextFieldDelegate>
@property (strong, nonatomic) PickerDataSource *pickerDataSource;
@property (strong, nonatomic) UIPickerView *picker;
@property (strong, nonatomic) UITextField *dummyTextField;
@end
Step three
In your viewDidLoad
, call [self setupPicker];
(you'll create this method next)
Step four
Create setupPicker
- (void)setupPicker {
// init custom picker data source
self.pickerDataSource = [PickerDataSource new];
// init custom picker
self.picker = [UIPickerView new];
// set the picker's dataSource and delegate to be your custom data source
self.picker.dataSource = self.pickerDataSource;
self.picker.delegate = self.pickerDataSource;
self.picker.showsSelectionIndicator = YES;
// next step is to write this configure method getting called here
[self configurePickerSubviews];
// lastly, add the dummyTextField to your view.
[self.view addSubview:self.dummyTextField];
}
Step five
Create configurePickerSubviews
- (void)configurePickerSubviews {
// A UIPickerView must be added as an inputView to a UITextField in order to be displayed on button tap
// So you need to create a dummyTextField to do so.
self.dummyTextField = [UITextField new];
// Create a toolbar to add a done button
UIToolbar *toolBar= [[UIToolbar alloc] initWithFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,44)];
[toolBar setBarStyle:UIBarStyleDefault];
UIBarButtonItem *done = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(locationPressed)];
// Create a flex space so that done button will be right aligned
UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *cancel = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(dismissPicker)];
toolBar.items = @[cancel, flex, done];
done.tintColor = [UIColor blackColor];
[self.picker addSubview:toolBar];
// Create an input view to add picker + done button as subviews
UIView *inputView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.picker.frame.size.height + 44)];
[self.picker setFrame:CGRectMake(0, 0, inputView.frame.size.width, inputView.frame.size.height)];
inputView.backgroundColor = [UIColor clearColor];
[inputView addSubview:self.picker];
[inputView addSubview:toolBar];
// Set custom inputView as container for picker view
self.dummyTextField.inputView = inputView;
// Hiding the textfield will hide the picker
[self.dummyTextField setHidden:YES];
}
Step six
Configure the PickerDataSource
so that it is fetching the data you want to display from your source array.
Step 7
Click Run
!