I have an UITextField in a MyCustomUIView class and when the UITextField loses focus, I'd like to hide the field and show something else in place.
The delegate for the UITextField is set to MyCustomUIView via IB and I also have 'Did End On Exit' and 'Editing Did End' events pointing to an IBAction method within MyCustomUIView.
#interface MyCustomUIView : UIView {
IBOutlet UITextField *myTextField;
}
-(IBAction)textFieldLostFocus:(UITextField *)textField;
#end
However, neither of these events seem to get fired when the UITextField loses focus. How do you trap/look for this event?
The delegate for the UITextField is set as MyCustomUIView so I am receiving textFieldShouldReturn message to dismiss the keyboard when done.
But what I'm also interested in is figuring when the user presses some other area on the screen (say another control or just blank area) and the text field has lost focus.
Try using delegate for the following method:
- (BOOL) textFieldShouldEndEditing:(UITextField *)textField {
NSLog(#"Lost Focus for content: %#", textField.text);
return YES;
}
That worked for me.
I believe you need to designate your view as a UITextField delegate like so:
#interface MyCustomUIView : UIView <UITextFieldDelegate> {
As an added bonus, this is how you get the keyboard to go away when they press the "done" or return buttons, depending on how you have set that property:
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
//This line dismisses the keyboard.
[theTextField resignFirstResponder];
//Your view manipulation here if you moved the view up due to the keyboard etc.
return YES;
}
The problem with the resignFirstResponder solution solely is, that it can only be triggered by an explicit keyboard or UITextField event.
I was also looking for a "lost focus event" to hide the keyboard, if somewhere outside the textfield was tapped on.
The only close and practical "solution" I came across is, to disable interactions for other views until the user is finished with the editing (hitting done/return on the keyboard) but still to be able to jump between the textfields to make corrections without the need of sliding out and in the keyboard everytime.
The following snippet maybe useful to someone, who wants to do the same thing:
// disable all views but textfields
// assign this action to all textfields in IB for the event "Editing Did Begin"
-(IBAction) lockKeyboard : (id) sender {
for(UIView *v in [(UIView*)sender superview].subviews)
if (![v isKindOfClass:[UITextField class]]) v.userInteractionEnabled = NO;
}
// reenable interactions
// assign this action to all textfields in IB for the event "Did End On Exit"
-(IBAction) disMissKeyboard : (id) sender {
[(UIResponder*)sender resignFirstResponder]; // hide keyboard
for(UIView *v in [(UIView*)sender superview].subviews)
v.userInteractionEnabled = YES;
}
You might have to subclass the UITextField and override resignFirstResponder. resignFirstResponder will be called just as the text field is losing focus.
i think you have implemented UIKeyboardDidHideNotification and in this event you
use code like
[theTextField resignFirstResponder];
remove this code.
also same code write in textFieldShouldReturn method. this also lost focus.
In Swift, you need to implement the UITextFieldDelegate to your ViewController and implement the method textFieldDidEndEditing from the delegate:
class ViewController: UIViewController, UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
// will be called when the text field loses their focus
}
}
Then you need to asign the delegate of your textField:
textField.delegate = self
For those struggling with this in Swift. We add a gesture recognizer to the ViewController's view so that when the view is tapped we dismiss the textfield. It is important to not cancel the subsequent clicks on the view.
Swift 2.3
override func viewDidLoad() {
//.....
let viewTapGestureRec = UITapGestureRecognizer(target: self, action: #selector(handleViewTap(_:)))
//this line is important
viewTapGestureRec.cancelsTouchesInView = false
self.view.addGestureRecognizer(viewTapGestureRec)
//.....
}
func handleViewTap(recognizer: UIGestureRecognizer) {
myTextField.resignFirstResponder()
}
Related
This question already has an answer here:
Issue related to textfield and datepicker
(1 answer)
Closed 6 years ago.
I have two textFields. On click, the first one is showing a qwerty keyboard and the second one is showing picker.
My issue is when I'm clicking on my first textField, the keyboard is showing properly. Now, After I type anything, I directly want to click on the second textField which is the showing picker and the keyboard should disappear, but the keyboard is still there.
I want to hide the keyboard as soon as I click on the second textField.
There are two ways to achieve this -
First: Use the UITextFieldDelegate.
For that-
List the UITextFieldDelegate in your view Controller's protocol list like,
#interface ViewController : UIViewController <UITextFieldDelegate>
Then make your ViewController conform to the Textfield's delegate to implement the methods like textFieldDidBeginEditing, and textFieldDidEndEditing:
So, go to the viewDidLoad method and conform to the UITextField's protocol like-
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstTextField.delegate = self; //assuming your first textfield's
//name is firstTextField
//Also give your first textfield a tag to identify later
self.firstTextField.tag = 1;
}
Now, you are set to implement the delegate methods. But, to achieve your target first, you need to take a UITextField instance to know when you are typing in the firstTextField. So, declare a property of UITextField type. Do that in the interface file like-
#property(nonatomic, strong) UITextField *currentTextField;
Now in the textFieldDidBeginEditing delegate method, assign the firstTextField instance to the currentTextField when you start typing in it like-
- (void)textFieldDidBeginEditing:(UITextField *)textField{
if(textField.tag == 1){
self.currentTextField = textField;
}
}
After that in the textFieldDidEndEditing method, check if it is the current textfield from which you are coming out and dismiss the keyboard like-
-(void)textFieldDidEndEditing:(UITextField *)textField{
if(textField.tag == 1){
[self.currentTextField resignFirstResponder];
}
return YES;
}
Second: You can use UIResponder. As ViewControllers inherit from UIResponder, you just override the method- touchesBegan:withEvent method, something like-
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];// this will do the trick
}
In this case, when you click out side the textField, the keyboard should automatically disappear.
use UITextFieldDelegate set delegate to self in ViewDidLoad and then put this code
func textFieldDidEndEditing(textField: UITextField)
{
yourtextfieldname.resignFirstResponder()
return true
}
Step 1 :- Code for ViewController.h :-
//add UITextFieldDelegate just after UIViewController
#interface ViewController : UIViewController<UITextFieldDelegate>
Step 2 :- Code For ViewController.m :-
//inside viewdidLoad write following code, where txtInput is outlet for input text field
_txtInput.delegate = self;
// Last Thing write following code just above #end
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
//that's it use this very simple way
Textfield containes a data picker. And because picker has no Return button, I have to close inputView somehow. I do not want to use inputAccessoryView so I though if user press again textfield should dismiss textfield. But I do not know how detect touch event. I subclassed UITextField and overwritten touchesBegan method, but it never get called even dow if I set userInteractionEnabled to false.
I tried to set up a tap gesture recognizer, first it fires, but second times not.
class TextFieldCloseWhenTouched: UITextField {
override func didMoveToWindow() {
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "tapped"))
}
func tapped() {
if self.isFirstResponder() {
self.resignFirstResponder()
} else {
self.becomeFirstResponder()
}
}
}
You can achieve this using the delegate function (BOOL)textFieldShouldBeginEditing:(UITextField *)textField without subclassing textfield, but then you will need to handle adding and removing the picker to the view with animation yourself, not as input view.
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if(isTextFieldOpen){
[self dismissDataPicker];
}
else{
[self showDataPicker];
}
isTextFieldOpen=!isTextFieldOpen;
return NO;
}
However, I don't think that this is the best user experience to make. I think it's better to either add the data picker to UIView with toolbar that has Done/Cancel button(s), or add a tap gesture recognizer to the main view when the data picker is shown so when the user tap anywhere it's dismissed.
If this is the only textfield in your screen, or you are okay to dismiss all by tapping anywhere, you can just add the following to your viewcontroller
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
[self.view endEditing:YES];
}
I am stumped and I hope someone can help.
I am calling the resign first responder method for all five of my text fields prior to a segue. The segue occurs, if the keyboard was visible prior to the segue, the keyboard remains no matter what I do. This did not happen in IOS6. It is only happening in IOS7.
Thank you so much in advance for your assistance.
Here is the scenario:
The user touches one text field at time to enter data. The keyboard has no problems changing from first responder from one field to the next and can be resigned from the DONE button without issues. The problem comes when the user touches a field that will be populated from the picker view. If the keyboard was visible from one of the previous text fields, it won't go away.
I have this code attempting to resignFirstResponder on the editingDidBegin action of two of the fields. I am using these two fields to hold numbers but I am filling them from a picker on the next view.
- (IBAction)txtRatioOrHullTypeTouched:(id)sender
{
// Hide the keyboard before the segue to the picker occurs.
[self.txtPitch resignFirstResponder];
[self.txtRPM resignFirstResponder];
[self.txtSlipOrSpeed resignFirstResponder];
[self.txtRatio resignFirstResponder];
[self.txtHullType resignFirstResponder];
segueToPicker = YES; // Raise flag indicating that this segue is to the picker.
[self performSegueWithIdentifier:#"toPicker" sender:sender];
}
I also put this same code in the viewWillDisappear as shown here:
- (void)viewWillDisappear:(BOOL)animated // Unchanged
{
// Hide the keyboard before the segue to the picker occurs.
[self.txtPitch resignFirstResponder];
[self.txtRPM resignFirstResponder];
[self.txtSlipOrSpeed resignFirstResponder];
[self.txtRatio resignFirstResponder];
[self.txtHullType resignFirstResponder];
[super viewWillDisappear:animated];
}
Both of these methods are on the initial view, ViewController.m file.
I ended up here removing the text field causing the problem and replacing them with buttons. No scenario I tried (dozens) got this code to work as expected in IOS7, even though it all worked flawlessly in IOS6.
I tried all of the above and it worked as long as i dismissed the controller with a button. The function that was called when pressing the button could call the TextField's resignFirstResponder() function and all was well.
However, when an edge swipe was performed to dismiss the controller the keyboard kept popping up the next time I showed it. In my code I reuse the same controller between views. This might not be wise but, it's snappy!
After trying everything the internet had written (well not really, but pretty close) about this I found that i could implement the TextField's textViewShouldBeginEditing() and return false between the ViewControllers ViewDidDisappear and ViewDidAppear. It's ha hack, but it did the trick when nothing else worked.
I hope this helps you guys!
Swift code:
In my ViewController
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
myTextField.allowEdit = true
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
myTextField.allowEdit = false
}
In my TextField class
class MyTextField: UIView, UITextFieldDelegate {
var allowEdit = true
func textFieldShouldBeginEditing(textView: UITextView) -> Bool {
return allowEdit
}
}
You can call endEditing: on the view controller with the text fields. Your viewWillDisappear: method will look like this:
- (void)viewWillDisappear:(BOOL)animated
{
[self.view endEditing:YES];
[super viewWillDisappear:animated];
}
Contributing my 2 cents worth. dismissing keyboard correctly on iOS 9.2, a minimalist sample, FYI.
...
#property (assign) BOOL isTransitioning;
...
-(void)viewWillAppear:(BOOL) animated {
self.isTransitioning = YES;
}
-(void)viewWillDisappear:(BOOL) animated {
self.isTransitioning = YES;
}
-(void)viewDidAppear:(BOOL) animated {
self.isTransitioning = NO;
}
-(void)viewDidDisappear:(BOOL) animated {
self.isTransitioning = NO;
}
-(BOOL) textViewShouldBeginEditing:(UITextView*) tv {
if (self.isTransitioning) {
return NO;
}
return YES;
}
I think due to the way you are leaving the view through a picker, without going through an exit, you need to include the following in your viewController:
- (BOOL) disablesAutomaticKeyboardDismissal
{
return NO;
}
Swift, 2017
override var disablesAutomaticKeyboardDismissal: Bool {
get { return false }
set { }
}
So it seems now that the text field that controls the keyboard will not allow resignation. I used the canResignFirstResponder query on that field and the result (boolean) was FALSE. I also noticed that i get a flashing cursor in the field even after the resignFirstResponder is called. – Larry J Oct 25 '13 at 23:32
I know this is old, but I had a similar issue and wanted to share what worked for me in case it might help anyone else:
After reading the above comment I found that moving [self.view endEditing:YES] from where I had it in textFieldDidBeginEditing to textFieldSHOULDBeginEditing did the trick for me. Now the keyboard is dismissing properly before my segue.
Taking Zaheer's comment into Swift this works very well for me.
view.endEditing(true)
This is a problem i have frequently. My best method to cope is creating a clear button under the keyboard and having that call a dismiss helper. Control the clear button by toggling its isHidden property. Tapping outside the keyboard will hit that clear button and call the dismiss helper. What it won't do is trigger your segue, the user will need to tap again to navigate out but that keyboard will be gone.
in viewDidLoad():
var clearButton: UIButton!
self.clearButton = UIButton(frame: self.view.frame)
self.clearButton.backgroundColor = .clear
self.clearButton.addTarget(self, action: #selector(self.dismissHelper(_:)), for: .touchUpInside)
self.view.addSubview(self.clearButton)
self.clearButton.isHidden = true
Then add the dismiss helper:
func dismissHelper(_ sender: UIButton?) {
self.clearButton.isHidden = true
view.endEditing(true)
}
func displayClearButton(){
print("display clear button, hidden = false")
self.clearButton.isHidden = false
}
then on your textfield add the target
self.textField.addTarget(self, action: #selector(self.displayClearButton), for: .editingDidBegin)
I'm trying to get rid of the keyboard when the user touch outside my UITextField, by using this method:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[mainTextController resignFirstResponder];
[super touchesBegan:touches withEvent:event];
}
However, this seems to call a method that is called after pressing the return button on the keyboard, but I just want the keyboard to vanish, not to press return for me.
How can I accomplish that?
Thanks!
EDIT: tGilani's answer is the most straight-forward way, works like a charm, without changing to UIControl. But I guess jonkroll's answer also works.
try
[self.view endEditing:YES];
Update:
Take a boolean value and set it to false in init method. In your textFieldShouldReturn delegate method method, execute the code if it is false, skip otherwise
- (BOOL) textFieldShouldReturn:(UITextField*)textField
{
if (!boolean)
{
// YOur code logic here
}
boolean = false;
}
in your method where you call the endEditing method, set boolean to true.
boolean = YES;
[self.view endEditing:YES];
Here's how I've handled this before. First create a method on your view controller that will dismiss the keyboard by resigning first responder status on your text field:
- (IBAction)dismissKeyboard:(id)sender
{
[mainTextController resignFirstResponder];
}
Next, in your storyboard scene for your ViewController (or nib, if you are not using storyboards) change the class of your ViewController's view property from UIView to UIControl. The view property is effectively the background behind your other UI elements. The class type needs to be changed because UIView cannot respond to touch events, but UIControl (which is a direct subclass of UIView) can respond to them.
Finally, in your ViewController's viewDidLoad: method, tell your view controller to execute your dismissKeyboard method when the view receives a UIControlEventTouchDown event.
- (void)viewDidLoad
{
[super viewDidLoad];
UIControl *viewControl = (UIControl*)self.view;
[viewControl addTarget:self action:#selector(dismissKeyboard:) forControlEvents:UIControlEventTouchDown];
}
EDIT:
Part of your concern seems to be that textFieldDidEndEditing: is called when the keyboard is dismissed. That is unavoidable, it will always be called whenever a text field loses focus (i.e. first responder status). It sounds like your problem is that you have put code to perform when the user clicks the return button in textFieldDidEndEditing:. If you do not want that code to run when the user touches outside of the text field, that is not the proper place to put it.
Instead, I would put that code in a separate method:
- (IBAction)textFieldReturn:(id)sender
{
if ([mainTextController isFirstResponder]) {
[mainTextController resignFirstResponder];
// put code to run after return key pressed here...
}
}
}
and then call that method via Target-Action when your text field sends the control event UIControlEventEditingDidEndOnExit.
[mainTextController addTarget:self action:#selector(textFieldReturn:) forControlEvents:UIControlEventEditingDidEndOnExit];
Note that UIControlEventEditingDidEndOnExit is different than UIControlEventEditingDidEnd. The former is called when editing ends by the user touching outside the control, the latter is called when editing ends by the user pressing the return key.
You need to change your ViewController's view property from UIView to UIControl using the Identity Inspector:
From there, you simply create an IBAction and tell the textfield to dismiss (which I am assuming is your mainTextController). If mainTextController is not the textfield you want the keyboard to dismiss on then change the resignFirstReaponder method to your textfield like so.
- (IBAction)backgroundTap:(id)sender {
[myTextField resignFirstResponder];
}
then from there go back into your View Contoller's .xib file and connect the action to the Control View and select "Touch Down".
I have a UITextfield that i'd like to dismiss the keyboard for. I can't seem to make the keyboard go away no matter what code i use.
If you have multiple text fields and don't know which one is first responder (or you simply don't have access to the text fields from wherever you are writing this code) you can call endEditing: on the parent view containing the text fields.
In a view controller's method, it would look like this:
[self.view endEditing:YES];
The parameter forces the text field to resign first responder status. If you were using a delegate to perform validation and wanted to stop everything until the text field's contents were valid, you could also code it like this:
BOOL didEndEditing = [self.view endEditing:NO];
if (didEndEditing) {
// on to the next thing...
} else {
// text field must have said to first responder status: "never wanna give you up, never wanna let you down"
}
The endEditing: method is much better than telling individual text fields to resignFirstResponder, but for some reason I never even found out about it until recently.
[myTextField resignFirstResponder]
Here, second paragraph in the Showing and Hiding the Keyboard section.
I've discovered a case where endEditing and resignFirstResponder fail. This has worked for me in those cases.
ObjC
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
[self setEditing:NO];
Swift
UIApplication.shared.sendAction(#selector(resignFirstResponder), to: nil, from: nil, for: nil)
There are cases where no text field is the first responder but the keyboard is on screen.
In these cases, the above methods fail to dismiss the keyboard.
One example of how to get there:
push the ABPersonViewController on screen programmatically; open any contact;
touch the "note" field (which becomes first responder and fires up the keyboard);
swipe left on any other field to make the "delete" button appear;
by this point you have no first responder among the text fields (just check programmatically) but the keyboard is still there. Calling [view endEditing:YES] does nothing.
In this case you also need to ask the view controller to exit the editing mode:
[viewController setEditing:NO animated:YES];
I suggest you add and action on your header file:
-(IBAction)removeKeyboard;
And in the implementation, write something like this:
-(IBAction)removeKeyboard
{
[self.textfield resignFirstResponder];
}
In the NIB file, connect from the UITextFiled to the File's Owner on the option DidEndOnExit. That way, when you press return, the keyboard will disappear.
Hope it helps!
In your view controller YourViewController.h file, make sure you implement UITextFieldDelegate protocol :
#interface YourViewController : <UITextFieldDelegate>
#end
Then, in YourViewController.m file, implement the following instance method:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.yourTextField1 resignFirstResponder];
[self.yourTextField2 resignFirstResponder];
...
[self.yourTextFieldn resignFirstResponder];
}
To resign any text field in the app
UIApplication.shared.keyWindow?.endEditing(true)
This approach is clean and guarantied to work because the keyWindow is, by definition, the root view of all possible views displaying a keyboard (source):
The key window receives keyboard and other non-touch related events. Only one window at a time may be the key window.
This will resign one particular text field
// Swift
TextField.resignFirstResponder()
// Objective C
[TextField resignFirstResponder];
To resign any text field use below code
// Swift
self.view!.endEditing(true)
// Objective C
[self.view endEditing:YES];
as a last resort 💩
let dummyTextView = UITextView(frame: .zero)
view.addSubview(dummyTextView)
dummyTextView.becomeFirstResponder()
dummyTextView.resignFirstResponder()
dummyTextView.removeFromSuperview()
If you don't know which textField is the first responder you can find it. I use this function:
UIView *resignFirstResponder(UIView *theView)
{
if([theView isFirstResponder])
{
[theView resignFirstResponder];
return theView;
}
for(UIView *subview in theView.subviews)
{
UIView *result = resignFirstResponder(subview);
if(result) return result;
}
return nil;
}
Then in your code call:
UIView *resigned = resignFirstResponder([UIScreen mainScreen]);
You just replace yourTextFieldName with, you guessed it! your textfield. This will close the keyboard.
[yourTextFieldName resignFirstResponder];
-(void)methodName
{
[textFieldName resignFirstResponder];
}
call this method (methodName) with didEndOnExit
For Swift 3
You can hide the keyboard like this:
textField.resignFirstResponder()
If you want to hide the keyboard when the user press the "intro" button, you have to implement the following UITextFieldDelegate method:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
// your code
[textField reloadInputViews];
}
3 Simple & Swift steps
Add UITextFieldDelegate to your class as below:
class RegisterVC: UIViewController, UITextFieldDelegate {
//class implementation
}
in class implementation, add the delegate function textFieldShouldEndEditing::
internal func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return true
}
and as a last step, set your UITextField(s) delegate(s) to self, in somewhere appropriate. For example, inside the viewDidLoad function:
override func viewDidLoad(){
super.viewDidLoad()
myTextField1.delegate = self
myTextField2.delegate = self
..
..
}
Now, whenever user hits the return key, keyboard will dismiss.
I prepared an example snippet too, you can check it from here.
Set up the "Did End On Exit" event in Xcode (right click on your text field).
Realize this method:
-(IBAction) closeKeyboard:(id) sender {
[_txtField resignFirstResponder];
}