I have implemented a scrolling feature, where the textfield is not hidden from the keyboard. Therefore I'm working with UIKeyboardDidShowNotification and UIKeyboardWillHideNotification, where the scrolling takes place. For the scrolling I need to know the current active textfield. This is done with EditingDidBegin and EditingDidEnd.
The code is in C# but there is no much difference:
usernameText.EditingDidBegin += delegate {
activeTextField = usernameText;
};
usernameText.EditingDidEnd += delegate {
activeTextField = null;
};
The flow of my application looks like the following:
User starts application and one textfield is becoming the first responder. The keyboard pops up and UIKeyboardDidShowNotification is correctly called.
User presses another button and another view is presented modally.
UIKeyboardWillHideNotification is called correctly as well as my active textfield is cleared out in EditingDidEnd.
When coming back from my modal view UIKeyboardDidShowNotification and UIKeyboardWillHideNotification are called again despite there is no keyboard active.
In UIKeyboardDidShowNotification I need the active text field which is null at that time and my app crashes. Now I used a null check for that so that the app doesn't crash.
But why are the two notifications are sent again when there is no need to?
in step 2: "User presses another button and another view is presented modally." before presenting a viewController hide Your keyboard
Related
I have a ViewController with a TextField for user input and a Quit button in a NavigationBar.
Normally, the user inputs text into the textField and the input is processed in textFieldDidEndEditing. If the Quit button is tapped before editing starts, then it segues correctly to the parent ViewController.
However, if editing has started on the textField and then the Quit button is tapped, textFieldDidEndEditing is still called, which I don't want to happen.
I have tried using textFieldDidEndEditing:reason: but the returned reason in both cases is UITextFieldDidEndEditingReasonCommitted. It seems that UITextFieldDidEndEditingReasonCancelled is only valid in tvOS not iOS.
How else can I detect that the user has Quit and prevent textFieldDidEndEditing from running to completion?
You can't prevent textFieldDidEndEditing from being called. Dismissing the view controller dismisses the text field. Since the text field is no longer being edited, the delegate method will be called.
One option you have is to set a flag when the user taps the Quit button. Then in your implementation of textFieldDidEndEditing you can check if that flag it set or not and act accordingly.
I know that the view controller must be firstResponder in order for the inputAccessory to stay at the bottom. I am using a custom inputView / keyboard. I can manually dismiss it with a done button by removing the inputView but not resigning first responder. However when I enable the interactive drag to dismiss on my scrollview, the code automatically resigns first responder. So how can I use the interactive drag to dismiss and yet keep my viewcontroller as first responder? Anyone done this before? I thought maybe it is not possible and that I may need to make my own interactive drag to dismiss using a gesture recognizer.
More info:
I have a button that swaps between standard keyboard and my custom one. I have seen dismissing these cause 2 keyboard did dismiss notifications. I thought I could become firstResponder in the keyboardDidHide method but this didn't work well since I couldn't tell the difference between when I manually dismissed the keyboard and when the interactive drag does it. This matters because I don't need to reload the input view or become first responder when I manually dismiss because I took care of it already.
Any suggestions would be amazing. I am trying to use inputView and inputAccessoryView on the UIViewController level.
Well after a day of pulling my hair, I have an answer.
Using the canResignFirstResponder of my viewcontroller did the trick. In viewWillAppear I set a BOOL responderOverride = YES;
In viewWillDisappear I call
responderOverride = NO;
[self resignFirstResponder];
When the interactive drag on the scrollview tries to resignFirstResponder, canResignFirstResponder returns no which prevents my viewcontroller from resigning and keeps my input accessory retained and sitting at the bottom of the screen.
There is a lot of other code with reloading input views but since the real question was how to force a controller to stay first responder so we don't lose our input accessory view, then this solution works.
override var canBecomeFirstResponder : Bool {
get {
retrun true
}
}
This works for me
In my iOS project, I have a form which contains various text fields. Some text fields are edited by keyboard and some by picker view which is placed on the popover.
When I go on filling text fields, without dismissing it and then if I click on popover text field keyboard remains open.
It appears as both keyboard and popover present on screen at the same time, which I don't want.
I am able to get whether the keyboard is opened or not by setting a flag in keyboard notification methods and also the last text field that was edited through text filed delegates. And have tried
[self endEditing: YES]; (as it is in a table cell)
[lastEditedTextField resignFirstResponder];
Even try to pass keyboard dismiss the notification by my self (without knowing whether it is possible or not)
[[NSNotificationCenter defaultCenter] postNotificationName:UIKeyboardWillHideNotification object:nil];
but nothing is working.
How can I dismiss keyboard (if already open) whenever popover appears?
You can call:
[self.view endEditing:YES];
But, a better solution is likely to present the picker using the UIResponder
inputView so it automatically replaces the keyboard and you don't need to mediate between 2 different things (and the user doesn't switch between different parts of the screen potentially).
Try to implement textFieldShouldBeginEditing: and inside it check which text field is this. If it is one of the fields that should display a popover, first call [self.view endEditing:YES] to hide the keyboard, then present the popover and return NO. This way the text field won't take first responder status and the keyboard will not appear again. And if it is one of the "normal" text fields, just return YES.
I'm new to iOS development and have recently learned that to make the on screen keyboard disappear we must always call resignFirstResponder on the text view. This causes the text view to relinquish it's first responder status, and hence the keyboard disappears, since there is no need for the text view to respond.
However I also noticed that there's the becomeFirstResponder method to make a view a first responder. However, this method is never called on the text view. So when/how does a textview become first responder when that method is never called?(at least, by me. I'm unsure if it is called elsewhere in the system)
My theory is that is has to already be a first responder before it can resign the first responder status.
firstResponder status is automatically handled for you when a user taps on the text field. So long as user interaction is enabled for the UITextField/UITextView, the keyboard should appear when tapped.
You can monitor for it using the delegate method textViewDidBeginEditiing or, more broadly, by listening for keyboard appearance notifications (UIKeyboardWillShowNotification and UIKeyboardDidShowNotification).
Further, there are ways to dismiss the keyboard without the need of calling the corresponding method resignFirstResponder (such as calling endEditing: on a container view, or setting a scroll view's UIScrollViewKeyboardDismissMode).
Note: In the simulator, it is possible that the keyboard still doesn't appear even if all is correctly working. In that case you just want to make sure keyboard hardware is toggled (CMD+K) for the simulator.
You call becomeFirstResponder yourself if you want to give a UITextField focus and show the keyboard.
This is useful for view controllers that are basically forms. For example, if a user presses a "Sign Up" button, you might push a view controller with a couple of text fields and call becomeFirstResponder on the first one to automatically give it focus and open the keyboard.
I had issue that every time when I enter a view controller - which is the "MessageListViewController" in the following screen-shot, the keyboard will be automatically popped out.
The thing is I used a UITextView in this MessageListViewController for text input, and when I pop this view controller from navigationController stack, if I leave the keyboard open, then the next time when it was pushed again, this keyboard will be popped out automatically.
If I make the text view resignFirstResponder before I popped out this view controller, then the next time enter it will be fine. However resignFirstResponder manually will make the keyboard dismissing with an ugly animation (manually dismiss keyboard it will make the keyboard always go downing the screen vertically, however the view controller popping transaction is horizontal, so it will look very wired)
I tried to build a simple sample to test the keyboard dismiss behavior - there are two view controllers, one is the rootViewController of the navigationController, and it will push another into the viewController stack, so the pushed view controller contains a UITextView, if I highlight the text view of the pushed one, then go back to the root view controller, the animation works just fine, also the keyboard won't be automatically popped out. So I just don't know why in my project, this keyboard always shows up unexpectedly if I just left the page without manually dismiss the keyboard.
BTW, the following call stack happened between viewWillAppear and viewDidAppear. It looks like triggered by iOS to restore the last state of the UITextView.
- (UIView*)findFirstResponder {
if (self.isFirstResponder) {
return self;
}
for (UIView* subview in self.subviews) {
UIView* ret = [subview findFirstResponder];
if (ret) {
return ret;
}
}
return nil;
}
NSLog(#"%#", [[[UIApplication sharedApplication] keyWindow] findFirstResponder]);
I also tried to track with the key window's first responder when this call stack triggered by keyboard will show notification, and the out put is just "nil".
Thanks guys for helping, I just realized where the problem is, actually I did not declare that the messagelistViewController which I used here is actually a singleton, so it never release even I pop the this out of the viewController stack.
Under that scenario, when the next time this view controller was appear again, the UIKit will be smart enough to restore the previous view state if it's not dealloced.
And in my test sample, I did not keep the test viewcontroller when it was popped out of stack.
so that's why this works fine for my test sample.
Then my final solution is kinda simple, just remove the textview from it's superview when the view did disappear, and then re-add this back when the view will appear.
It turns out my question is a little bit stupid, however it do let me know two things:
1) The view controller will restore to it's previous state every time when it appears if you not delete it
2) The keyboard dismiss animation will always be going down if manually resign the input from the first responder, if we don't want this effect, we shall never dismiss it manually.
I created a demo in iOS 7 as per you said in your question, it was working fine for me even I didn't have to call resignFirstResponder method for resigning keyboard. So you could look in your code as you might have been calling becomeFirstResponder somewhere making the keyboard to be active again or simply post your code here so I could have a look at it.