[ Get UIAlertView to respond to return on keyboard with same result as OK button ]
I would like to run the same code if the button on the alert is pressed, or the return key on the keyboard is pressed.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
works for the OK button on the alert, but I can not find an equivalent for the return key.
I have been experimenting with - (BOOL)textFieldShouldReturn:(UITextField *)alertTextField
, to no avail.
A year ago, three people in the comments on this site had the same problem and it was not answered:
How do you get the alertview to respond to a "Return" on the keyboard with the same result as tapping the "OK" button? I can't seem to find anything for the iOS 5 SDK on Google.
What are all the steps necessary to accomplish this?
Edit:
More specifically:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[[NSUserDefaults standardUserDefaults] setObject:[alertView textFieldAtIndex:0].text forKey:@"url_preference"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
When the user presses OK, that code is run. What is the similar, simple equivalent for the Return key on the keyboard?
Currently, I am trying this:
- (BOOL)textFieldShouldReturn:(UITextField *)alertTextField {
[alertTextField resignFirstResponder];
NSLog(@"test");
return YES;
}
Which does nothing.
This is the definition of my alert:
-(void) noUrl {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Add a URL" message:@"Change it later in Settings" delegate:self cancelButtonTitle:nil otherButtonTitles:@"Load",nil]; //If you change button name, change it in the other alertView function
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
UITextField * alertTextField = [alert textFieldAtIndex:0];
alertTextField.keyboardType = UIKeyboardTypeURL;
alertTextField.returnKeyType = UIReturnKeyGo;
alertTextField.enablesReturnKeyAutomatically = YES;
alertTextField.placeholder = @"http://www.example.com";
[alert show];
return;
}
If code needs to be added in another file, or another place, I would appreciate detailed specifics.
Answer 1
Set
[alert textFieldAtIndex:0].delegate = self;
and then implement
- (BOOL)textFieldShouldReturn:(UITextField *)alertTextField {//add any method you want to execute to here. This method will be called when user taps on the textfield in alertview.
[alertTextField resignFirstResponder];// to dismiss the keyboard.
[alert dismissWithClickedButtonIndex:0 animated:YES];//this is called on alertview to dismiss it.
}
Also put UITextFieldDelegate
in your .h file as,
@interface CustomViewController : UIViewController <UIAlertViewDelegate, UITextFieldDelegate>
As per the current edit in the question, you are missing,
alertTextField.delegate = self;
Update:
Based on your comment, make alert as a class level variable as,
@interface CustomViewController : UIViewController <UIAlertViewDelegate, UITextFieldDelegate> {
UIAlertView *alert;
}
Then change this method to,
-(void) noUrl {
alert = [[UIAlertView alloc] initWithTitle:@"Add a URL" message:@"Change it later in Settings" delegate:self cancelButtonTitle:nil otherButtonTitles:@"Load",nil]; //If you change button name, change it in the other alertView function
//rest of the code here...
Answer 2
Edit: Whole new answer based on the updated question.
Based on the updated question, ACB's answer will work. If the user taps the OK button on the alert view, the alert view delegate method will be called.
If the user taps return, the text field's delegate will be called, which in turn dismisses the alert view, which in turn calls the alert view delegate method.
So in both cases the alert view is dismissed and in both cases the alert view delegate method is called.
If you don't want the alert dismissed when the return key is tapped, then the answer is different. In this case, create a common method that you can call from both the alert view delegate method and the text field delegate method. And don't dismiss the alert view from the text field delegate method.
Answer 3
I am having this issue also and the solution presented looks fine, but somehow my [alertView dismissWithClickedButtonIdex:1 animated:YES]
closes the AlertView but does not call the AlertView's delegate method
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
//...
}
While clicking on the button properly calls the delegate UIAlertView method, pressing enter on the keyboard doesn't trigger it programmatically. What am I missing here?
Debugging shows the AlertView's delegate to be properly set inside the UITextFieldDelegate method, so we're not talking nil here either :P
Answer 4
There's a much easier way to do this, at least in iOS 10. I'm sure @iDev's answer works too, but I prefer this configuration-based approach.
I'm unsure what other versions of iOS this works on, or where in the API docs this behavior is documented (eg: it's not here).
Leaves alert open on keyboard dismiss:
If you add two actions, both with .default
style, closing the keyboard does not dismiss the alert or call any handler. eg:
let cancel = UIAlertAction(title: "Cancel", style: .default, handler: nil)
let ok = UIAlertAction(title: "Ok", style: .default, handler: nil)
// Both buttons are .default, so the framework doesn't know which action to take
This is not the behavior you want if you're reading this Q&A, but it's useful as a before and after example.
Fires .default
handler on keyboard dismiss:
If you set only one of your actions to .default
, dismissing the keyboard will automatically trigger the default action and close the alertView. eg:
let alert = UIAlertController(title: "Your Name", message: "What is your name?, preferredStyle: .alert)
// Note the `.cancel` style. This is key
let cancelBtn = UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) in print("cancel()") })
let okBtn = UIAlertAction(title: "Ok", style: .default, handler: { (action) in
let text = alert.textFields?[0].text ?? ""
print("User Entered: \(text)")
})
alert.addAction(cancelBtn)
alert.addAction(okBtn)
alert.preferredAction = okBtn // Make this button the highlighted/bold one
alert.addTextField {
$0.returnKeyType = .done // optional, but has appearance of a dismissing button
}
You can see I'm also setting preferredAction
so my cancel button isn't bold, and specifying that the keyboard's main button should be the bright blue "done" style. Neither of these is required for the default handler to be executed but seem like better UX to me.