Show keyboard with textField when pressing uibutton - ios

I have a button:
#property (weak, nonatomic) IBOutlet UIBarButtonItem *addTaskBtn;
...
// Add new task button action.
- (IBAction)addTaskBtnAction:(id)sender {
}
I want a keyboard with a textfield accessory toolbar to pop up when I press my button. That textfield should also become the firstresponder which causes kind of a paradox...
I find it impossible to show a keyboard without making it a first responder of an existing textfiled, but I am trying to create a textfield as a toolbar of a keyboard.
The best example for this is in this app: https://todoist.com/ - they managed to do exactly what I am trying to achieve.
Any ideas?

Try this code for the hidden textfield:
make txtHidden as hidden and make it first responder on button click
- (IBAction)btnOpenTextfield:(id)sender {
[self.txtHidden becomeFirstResponder];
}
- (void) setupToolbar {
UIToolbar *keyboardToolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 42)];
self.txtToolbar = [[UITextField alloc] initWithFrame:CGRectMake(8, 6, 250, 30)];
UIBarButtonItem *textBtn = [[UIBarButtonItem alloc] initWithCustomView:self.txtToolbar ];
UIBarButtonItem *postBtn = [[UIBarButtonItem alloc]initWithTitle:#"Post" style:UIBarButtonItemStyleBordered target:self action:#selector(postComment)];
[keyboardToolBar setItems: [NSArray arrayWithObjects:textBtn,postBtn,nil]];
self.txtHidden.inputAccessoryView = keyboardToolBar;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if (textField == self.txtHidden) {
[self setupToolbar];
}
return true;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[self performSelector:#selector(changeResponder) withObject:nil afterDelay:0.1];
[self changeResponder];
}
- (void) changeResponder {
[self.txtToolbar becomeFirstResponder];
}
This is not the best way but you can try this till you get any other better solution

Related

ios How to add an inputAccessoryView?

I am trying to replicate Facebook Messenger App, where there is a UITextView attached to the top of the keyboard.
Due to the nature of this app I need my view to be attached, instead of manually scrolling up and down a ScrollView when the keyboard appears.
This can be achieved by using a inputAccessoryView.
I read the docs on it here.
The documentation is very brief and says:
"This property is typically used to attach an accessory view to the system-supplied keyboard that is presented for UITextField and UITextView objects.
The value of this read-only property is nil. If you want to attach custom controls to a system-supplied input view (such as the system keyboard) or to a custom input view (one you provide in the inputView property), redeclare this property as read-write in a UIResponder subclass.
You can then use this property to manage a custom accessory view. When the receiver becomes the first responder, the responder infrastructure attaches the accessory view to the appropriate input view before displaying it."
I have tried declaring a property
#interface CommentViewController ()
#property (nonatomic, readwrite, retain) UIView *inputAccessoryView;
#end
And then setting it:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 20, 320, 100)];
[view setBackgroundColor:[UIColor greenColor]];
self.inputAccessoryView = view;
}
Then I have tried calling both of these:
[self.tableView becomeFirstResponder];
[view becomeFirstResponder];
Nothing happens. What am I doing wrong?
*Note - Extra information: I am using a UITableViewController that I want to have a UIView attached as an inputAccessoryView. Once I get the view working then I will add in a UITextView and more, but this is mainly an example.
Any help is greatly appreciated!
Add input accessory to your textField or textView rather than to pure UIView.
self.mytextField.inputAccessoryView = view;
The inputAccessoryView is a property of the UIResponder class. It allows you to define a custom input accessory view to display when the receiver becomes the first responder. Usually an instance of UIToolBar should be set as the accessory view.
A toolbar sample:
MYInputAccessoryToolbar.h
typedef void (^MYInputAccessoryToolbarDidDoneTap)(id activeItem);
#interface MYInputAccessoryToolbar : UIToolbar
#property (nonatomic, copy) MYInputAccessoryToolbarDidDoneTap didDoneTapBlock;
+ (instancetype)toolbarWithInputItems:(NSArray *)items;
- (instancetype)initWithInputItems:(NSArray *)items;
- (void)addInputItem:(id)item;
- (void)goToNextItem;
- (void)goToPrevItem;
#end
MYInputAccessoryToolbar.m
#interface MYInputAccessoryToolbar ()
#property (strong, nonatomic) UIBarButtonItem *nextButton;
#property (strong, nonatomic) UIBarButtonItem *prevButton;
#property (strong, nonatomic) UIBarButtonItem *doneButton;
#property (nonatomic, copy) NSMutableArray *inputItems;
#property (nonatomic) NSInteger activeItemIndex;
#property (nonatomic) id activeItem;
#end
#implementation MYInputAccessoryToolbar
+ (instancetype)toolbarWithInputItems:(NSArray *)items {
return [[self alloc] initWithInputItems:items];
}
#pragma mark - Initializations
- (instancetype)init {
self = [super init];
if (self) {
_inputItems = [NSMutableArray new];
_prevButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:101 target:self action:#selector(prevButtonTaped)];
_nextButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:102 target:self action:#selector(nextButtonTaped)];
_doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleBordered target:self action:#selector(doneButtonTaped)];
[_doneButton setTitleTextAttributes:#{NSFontAttributeName:[UIFont boldSystemFontOfSize:17]} forState:UIControlStateNormal];
UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
fixedSpace.width = 20.0f;
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
NSArray<UIBarButtonItem *> *barButtons = #[_prevButton, fixedSpace, _nextButton, flexSpace, _doneButton];
[self sizeToFit];
self.items = barButtons;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(itemDidBeginEditing:)
name:UITextFieldTextDidBeginEditingNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(itemDidBeginEditing:)
name:UITextViewTextDidBeginEditingNotification
object:nil];
}
return self;
}
- (instancetype) initWithInputItems:(NSArray *)items {
self = [self init];
for (id item in items) {
[self addInputItem:item];
}
return self;
}
#pragma mark - Accessors
- (void)addInputItem:(id)item {
if ([item respondsToSelector:#selector(setInputAccessoryView:)]) {
[item setInputAccessoryView:self];
}
[_inputItems addObject:item];
}
#pragma mark - Actions
- (void)itemDidBeginEditing:(NSNotification *)noticifation {
NSInteger itemIndex = [_inputItems indexOfObject:noticifation.object];
if (itemIndex != NSNotFound && _activeItem != noticifation.object) {
_activeItemIndex = itemIndex;
_activeItem = noticifation.object;
[self activeItemChanged];
}
}
- (void)activeItemChanged {
_prevButton.enabled = _activeItemIndex != 0;
_nextButton.enabled = _activeItemIndex != _inputItems.count - 1;
}
- (void)prevButtonTaped {
[self goToPrevItem];
}
- (void)nextButtonTaped {
[self goToNextItem];
}
- (void)goToNextItem {
[_inputItems[_activeItemIndex + 1] becomeFirstResponder];
}
- (void)goToPrevItem {
[_inputItems[_activeItemIndex - 1] becomeFirstResponder];
}
- (void)doneButtonTaped {
if (_didDoneTapBlock) {
_didDoneTapBlock(_activeItem);
}
[_activeItem resignFirstResponder];
}
#pragma mark - Dealloc
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidBeginEditingNotification object:nil];
}
#end
Now assuming that we have a set of text field fields and text views we could use them to initialize an instance of our toolbar.
MYInputAccessoryToolbar *accessoryToolbar = [MYInputAccessoryToolbar toolbarWithInputItems:#[_passwordCurrentField, _passwordNewField, _passwordVerifyField]];
And then each of these fields will have a custom accessory view like this.
Remove self.inputAccessoryView = view; and then add the code below anywhere after -(void)viewDidLoad { ... } where view is your UIView:
-(void) viewDidLoad {
....
}
- (UIView *)inputAccessoryView
{
return self.view;
}
I am posting this answer to show other people my exact code and how easy it actually was, however all the credit goes to MadNik.
In your view controller class where you want a keyboard, in the implementation add the following:
#implementation CommentViewController {
UIView *toolbar;
UITextView *commentTextView;
UIButton *postComment;
}
The toolbar is the actual view that gets docked to your keyboard, and the rest of the objects go on top of the view.
Next it is as simple as initiating the toolbar and setting its frame:
toolbar = [[UIView alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height-50, self.view.frame.size.width, 50)];
[toolbar setBackgroundColor:[UIColor whiteColor]];
I make the frame of the toolbar initially sit right at the bottom of the view controller.
Next I just initiate the rest of the objects I want on my toolbar, e.g the UITextField and a UIButton. Just lay them out how you want:
commentTextView = [[UITextView alloc]initWithFrame:CGRectMake(8, 8, self.view.frame.size.width - 16 - 75, 34)];
[commentTextView setBackgroundColor:[UIColor colorWithWhite:0.97 alpha:1]];
commentTextView.layer.cornerRadius = 5;
[commentTextView setFont:[UIFont fontWithName:#"Avenir Next" size:20]];
[commentTextView setTextColor:[UIColor colorWithWhite:0.35 alpha:1]];
postComment = [[UIButton alloc]initWithFrame:CGRectMake(self.view.frame.size.width-75, 0, 75, 50)];
[postComment setTitle:#"Post" forState:UIControlStateNormal];
[postComment.titleLabel setFont:[UIFont fontWithName:#"Avenir Next" size:20]];
[postComment setTitleColor:[UIColor colorWithRed:(255/255.0) green:(40/255.0) blue:(80/255.0) alpha:1.0] forState:UIControlStateNormal];
Next add your objects to your tool bar:
[toolbar addSubview:commentTextView];
[toolbar addSubview:postComment];
Now this is where the magic happens: You simply set your UITextView's inputAccessoryView to whatever view you want to be docked to the keyboard.
In this case it is toolbar, because the toolbar is acting as a dock that holds everything else.
Now all you need to do is add your toolbar to your view controller, and when you tap the UITextView, since its inputAccessoryView it the toolbar, the toolbar will be docked to the keyboard!
Since I am using a UITableViewController, I had to add my toolbar to the window:
[[[UIApplication sharedApplication]delegate].window addSubview:toolbar];
So simple! No extra classes or anything needs to be made!

Sliding the keyboard to the left in iOS

I'm wondering if there is a way to slide the first-responder keyboard to the left or to the right when the user press a button.
http://cl.ly/image/143K3t403d1m/1.png
I make the button as a keyboard-accessory view. When it's tapped the keyboard should slide to the left displaying another custom inputs panel.
Any ideas?
If you want a keyboard that can be selected from the system (using the globe key), you'll need to read this article about creating a Custom Keyboard App Extension for iOS 8.
If you just want to be able to switch between inputView objects, the following code will get you there:
// ViewController.m
#import "ViewController.h"
#interface ViewController () {
}
#pragma mark -
#pragma mark - UI Controls
#property (strong, nonatomic) UIInputView *inputView;
#property (strong, nonatomic) UITextField *textField;
#end
#implementation ViewController
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
#pragma mark -
#pragma mark - Keyboard switching
- (void)switchKeyboard {
// Simply toggle the "inputView" for self.textField
if (self.textField.inputView == nil) {
self.textField.inputView = self.inputView;
} else {
self.textField.inputView = nil;
}
[self.textField resignFirstResponder];
[self.textField becomeFirstResponder];
}
#pragma mark -
#pragma mark - UI Setup
// All of the code below here
// is for pure, in-code AutoLayout
- (void)setupUserInterface {
[self createControls];
[self setupControls];
[self layoutControls];
}
- (void)createControls {
self.textField = [[UITextField alloc] init];
self.textField.borderStyle = UITextBorderStyleRoundedRect;
self.inputView = [[UIInputView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 216.0f)];
self.inputView.backgroundColor = [UIColor lightGrayColor];
}
- (void)setupControls {
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44.0f)];
toolbar.backgroundColor = [UIColor lightGrayColor];
// When the button is tapped, it'll execute "switchKeyboard" above
UIBarButtonItem *switchButton = [[UIBarButtonItem alloc] initWithTitle:#"Switch" style:UIBarButtonItemStyleDone target:self action:#selector(switchKeyboard)];
toolbar.items = #[switchButton];
self.textField.inputAccessoryView = toolbar;
[self.textField setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (void)layoutControls {
[self.view addSubview:self.textField];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[textfield]-|"
options:0
metrics:nil
views:#{#"textfield": self.textField}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(height)-[textfield(==height)]"
options:0
metrics:#{#"height" : #(40)}
views:#{#"textfield": self.textField}]];
}
#end
Caveat: You will need to do a lot of tweaking to make sure the user experience is good. In my testing, on the simulator (iPhone 4S), this works ok, but isn't the smoothest user experience.

Configure "Done" button for multiple picker views

I have a scene in which I want to use picker views to get the input for multiple text boxes. I want each picker view to have a toolbar with a "Done" button that dismisses the picker view. So far I have:
//toolbar with "Done" button for picker views
UIToolbar *pickerToolBar= [[UIToolbar alloc] initWithFrame:CGRectMake(0,0,320,44)];
[pickerToolBar setBarStyle:UIBarStyleBlackOpaque];
UIBarButtonItem *barButtonDone = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(doneWithPicker:)];
pickerToolBar.items = [[NSArray alloc] initWithObjects:barButtonDone,nil];
barButtonDone.tintColor=[UIColor blackColor];
//set up picker views
_pickerOne = [[UIPickerView alloc] init];
_pickerOne.dataSource = self;
_pickerOne.delegate = self;
self.textFieldOne.inputView = self.pickerOne;
self.textFieldOne.inputAccessoryView = pickerToolBar;
What I need is some way for the doneWithPicker method to figure out which text field is currently being edited and call resignFirstResponder.
Use the text field delegate to identify which field is active. (Make sure to set yourself up as the delegate)
#implementation WhateverViewController
{
UITextField *activeTextField;
}
...
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeTextField = textField;
}
Then, in the method that is called when your done button is tapped:
[activeTextField resignFirstResponder];

toolbar previous and next button logic

I'm using the following code to move to the next field using the UITextField delegate and also I'm adding a toolbar to the keyboard with the previous, next and ok buttons. The code is working fine.
Like you see the keyboard return button logic is pretty generic, using the UITextField tags, and that's good because I'm gonna use the piece of code all around. Now I will need to write the previous and next buttons logic, and I'm lost. Any ideas?
UPDATE (complete code, with some modifications, thanks to #8vius that spent some time with me in the chat to make it work):
//
// SigninViewController.m
//
#import "SigninViewController.h"
#implementation SigninViewController
#synthesize firstResponder = _firstResponder;
#synthesize toolbar;
#synthesize email;
#synthesize password;
- (void)move:(UIBarButtonItem*)sender {
NSInteger tag = self.firstResponder.tag;
if ([sender.title isEqualToString:#"Anterior"]) {
tag -= 1;
} else if ([sender.title isEqualToString:#"Próximo"]) {
tag += 1;
}
UITextField *nextTextField = (UITextField*)[self.view viewWithTag:tag];
if (nextTextField && tag > 0) {
[nextTextField becomeFirstResponder];
} else {
[self.firstResponder resignFirstResponder];
self.firstResponder = nil;
}
}
- (void)ok:(id)sender {
[self.view endEditing:YES];
self.firstResponder = nil;
}
- (void)textFieldDidBeginEditing:(UITextField*)textField {
self.firstResponder = textField;
}
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
NSInteger tag = textField.tag + 1;
UITextField *nextTextField = (UITextField*)[self.view viewWithTag:tag];
if (nextTextField) {
[nextTextField becomeFirstResponder];
} else {
[textField resignFirstResponder];
self.firstResponder = nil;
}
return NO;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.email.delegate = self;
self.password.delegate = self;
if (self.toolbar == nil)
{
self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
UIBarButtonItem* previous = [[UIBarButtonItem alloc] initWithTitle:#"Anterior" style:UIBarButtonItemStyleBordered target:self action:#selector(move:)];
UIBarButtonItem* next = [[UIBarButtonItem alloc] initWithTitle:#"Próximo" style:UIBarButtonItemStyleBordered target:self action:#selector(move:)];
UIBarButtonItem* space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:(UIBarButtonSystemItemFlexibleSpace) target:nil action:nil];
UIBarButtonItem* ok = [[UIBarButtonItem alloc] initWithTitle:#"Ok" style:UIBarButtonItemStyleBordered target:self action:#selector(ok:)];
[self.toolbar setItems:[[NSArray alloc] initWithObjects:previous, next, space, ok, nil]];
[self.toolbar setTranslucent:YES];
[self.toolbar setTintColor:[UIColor blackColor]];
}
for (UIView* view in self.view.subviews) {
if ([view isKindOfClass:[UITextField class]]) {
[(UITextField*)view setInputAccessoryView:toolbar];
}
}
}
- (void)viewDidUnload {
self.email = nil;
self.password = nil;
[super viewDidUnload];
}
#end
It's quite simple, when you load your view you set the tag property on your text fields depending on the order you want them in, then you have to just traverse the tag element on the fields:
- (void)toggleTextfield:(UIBarButtonItem *)sender {
NSInteger nextTag = self.firstResponder.tag;
if ([sender.title isEqualToString:#"Previous"] && nextTag > 1) {
nextTag -= 1
} else if ([sender.title isEqualToString:#"Next"]) {
nextTag += 1;
}
UITextField *nextTextField = (UITextField *)[self.view viewWithTag:nextTag];
if (nextTextField) {
[nextTextField becomeFirstResponder];
}
}
And keep track of who is the first responder:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
self.firstResponder = textField;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
self.firstResponder = nil;
return YES;
}
And when you load your view, you bind the buttons to the toggle action:
UIBarButtonItem *previousButton = [[UIBarButtonItem alloc] initWithTitle:#"Previous"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(toggleTextfield:)];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithTitle:#"Next"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(toggleTextfield:)];
In my case, for instance, I set up my text fields inside a table view, so in my cellForRowAtIndexPath method I set the tag property to be the row of the indexPath.
EDIT: You have to set the firstResponder property for it to work.
In your .h file:
#property UIView *firstResponder
In your .m file:
#synthesize firstResponder = _firstResponder;

How to Show UIPickerView when selecting UITextField

Here is a screenshot of what I did till now:
So what I am trying to do is when you select "pick a name" Textfield I need a Picker to show up, with the input #"Jack".
Since iOS 3.2, UITextField supports the inputView property to assign a custom view to be used as a keyboard, which provides a way to display a UIPickerView:
You could use the inputView property of the UITextField, probably combined with the inputAccessoryView property. You assign your pickerView to the inputView property, and, to dismiss the picker, a done button to the inputAccessoryView property.
UIPickerView *myPickerView = [[UIPickerView alloc] init];
//myPickerView configuration here...
myTextField.inputView = myPickerView;
Like that. This will not give you a direct way to dismiss the view since your UIPickerView has no return button, which is why I recommend to use the inputAccessoryView property to display a toolbar with a done button (the bar is just for aesthetics, you might as well just use a UIButton object):
UIToolbar *myToolbar = [[UIToolbar alloc] initWithFrame:
CGRectMake(0,0, 320, 44)]; //should code with variables to support view resizing
UIBarButtonItem *doneButton =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(inputAccessoryViewDidFinish)];
//using default text field delegate method here, here you could call
//myTextField.resignFirstResponder to dismiss the views
[myToolbar setItems:[NSArray arrayWithObject: doneButton] animated:NO];
myTextField.inputAccessoryView = myToolbar;
I use this and find this a lot cleaner than adding a subview and animating the UIPicker
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
responder = textField;
if ([textField isEqual:self.txtBirthday]) {
UIDatePicker *datepicker = [[UIDatePicker alloc] initWithFrame:CGRectZero];
[datepicker setDatePickerMode:UIDatePickerModeDate];
textField.inputView = datepicker;
}
return YES;
}
it will work for you .. i have edited it .and for that you have to set delegate for textfield. and create a UIPIckrView in NIb file.
- (BOOL) textFieldShouldBeginEditing:(UITextView *)textView
{
pickrView.frame = CGRectMake(0, 500, pickrView.frame.size.width, pickrView.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.50];
[UIView setAnimationDelegate:self];
pickrView.frame = CGRectMake(0, 200, pickrView.frame.size.width, pickrView.frame.size.height);
[self.view addSubview:pickrView];
[UIView commitAnimations];
return NO;
}
Well, you could rely on the UITextFieldDelegate to handle this kind of functionality.
Inside the
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
is where you would set the text of your current UITextField as well as initializing and showing the UIPickerView.
Important notice:
You might also want to conform to the UIPickerViewDelegate.
HTH
Swift:
internal var textFieldHandlerToolBar: UIToolbar = {
let tb = UIToolbar.init(frame: CGRect.init(origin: .zero, size: CGSize.init(width: UIScreen.main.bounds.width, height: 44.0)))
let doneBarButton = UIBarButtonItem.init(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(actionDonePickerSelection))
tb.setItems([doneBarButton], animated: false)
return tb
}()
internal var pickerView: UIPickerView = {
let pv = UIPickerView.init()
return pv
}()
#objc internal func actionDonePickerSelection() {
textField.resignFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
self.pickerView.delegate = self
self.pickerView.datasource = self
}
Use it like this:
textField.inputAccessoryView = self.textFieldHandlerToolBar
textField.inputView = self.pickerView
What you can do is, create a UIButton with custom type on UITextField. Both having equal sizes. On the touch of button you can show UIPickerView.
http://tmblr.co/ZjkSZteCOUBS
I have the code and everything laid out in my blog to do this exactly. But below, I have the basic concept laid out.
Basically the solution involves an opensource project called ActionSheetPicker on github, and implementing the function textFieldShouldBeginEditing on the UITextFieldDelegate. You can dismiss the keyboard there and provide a UIPickerView instead. The basic code is listed here:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
// We are now showing the UIPickerViewer instead
// Close the keypad if it is showing
[self.superview endEditing:YES];
// Function to show the picker view
[self showPickerViewer :array :pickerTitle];
// Return no so that no cursor is shown in the text box
return NO;
}
ViewController.h
#interface ChangeCurrencyVC : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
{
NSArray *availableCurreniesArray;
}
#property (weak, nonatomic) IBOutlet UITextField *chooseCurrencyTxtFldRef;
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
availableCurreniesArray = #[#"Indian Rupee", #"US Dollar", #"European Union Euro", #"Canadian Dollar", #"Australian Dollar", #"Singapore Dollar", #"British Pound", #"Japanese Yen"];
// Do any additional setup after loading the view.
[self pickerview:self];
}
#pragma mark - picker view Custom Method
-(void)pickerview:(id)sender{
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.chooseCurrencyTxtFldRef.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.chooseCurrencyTxtFldRef.inputAccessoryView = toolBar;
}
#pragma mark - doneTouched
- (void)cancelTouched:(UIBarButtonItem *)sender{
// hide the picker view
[self.chooseCurrencyTxtFldRef resignFirstResponder];
}
#pragma mark - doneTouched
- (void)doneTouched:(UIBarButtonItem *)sender{
// hide the picker view
[self.chooseCurrencyTxtFldRef resignFirstResponder];
// perform some action
}
#pragma mark - The Picker Challenge
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return [availableCurreniesArray count];
}
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow: (NSInteger)row forComponent:(NSInteger)component{
return availableCurreniesArray[row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.chooseCurrencyTxtFldRef.text = availableCurreniesArray[row];
}

Resources