Post UIKeyboardDidShowNotification manually - ios

Because the keyboard hides the textfields when coming up I implemented a solution for this. Now I also have built in the possibility that the user taps on the next button of the keyboard and directly jumps to the next textfield (tabbing between fields).
The problem now is that the view doesn't scroll if I use becomeFirstResponder only. The keyboard is up but the UIKeyboardDidShowNotification is not triggered and so the view doesn't slide up.
Can I fake such a notification so that the UIKeyboardDidShowNotification is sent by the notification center?

Another option is to use two great libraries for this. BSKeyboardControls for the tabbing and TPKeyboardAvoiding for moving the view.
If you just want to send the notification my guess is that [[NSNotificationCenter defaultCenter] postNotificationName: UIKeyboardDidShowNotification object:self] should work just fine.

The solution is simple:
resignFirstResponder
becomeFirstResponder
I can only provide the solution for C# (that's why I left it out first):
private bool TextFieldShouldReturn (UITextField textfield)
{
if (textfield.Tag == 1) {
UIResponder nextResponder = this.View.ViewWithTag (2);
textfield.ResignFirstResponder ();
nextResponder.BecomeFirstResponder ();
} else if(textfield.Tag == 2){
textfield.ResignFirstResponder ();
loginButton.SendActionForControlEvents (UIControlEvent.TouchUpInside);
} else {
// Not found, so remove keyboard.
textfield.ResignFirstResponder ();
}
return false; // We do not want UITextField to insert line-breaks.
}
I set some tags on each textfield. Than I use the delegate usernameText.ShouldReturn += TextFieldShouldReturn; to call my method TextFieldShouldReturn. This method selects the next textfield. To jump to the next text field you first dismiss the keyboard with resignFirstResponder and present the keyboard with becomeFirstResponder. With this code the UIKeyboardDidShowNotification is called like the user would tap on the textfield (= simulated tap).

Related

UIScrollView keyboard dismiss on drag doesn't call resignFirstResponder on UIView with custom inputView keyboard on iOS 11

I have a UIView which draws a signature. The signature is inputed via a custom inputView on the signature view.
When drawing the signature view, I use the fact that it's the first responder to highlight the view as being edited, and I also override the resignFirstResponder method to work out when to stop showing it as being edited.
So the code looks something like this:
#implementation SignatureView
-(BOOL) becomeFirstResponder {
BOOL result = [super becomeFirstResponder];
[self showEditingMode];
return result;
}
-(BOOL) resignFirstResponder {
BOOL result = [super resignFirstResponder];
[self showViewingMode];
return result;
}
-(UIView *) inputView {
if (!keyboard)
keyboard = [[SignatureKeyboardView alloc] initWithStuff:stuff....];
return keyboard;
}
#end
The problem I'm having is that on iOS 11, the resignFirstResponder method is no longer getting called. On previous versions of iOS, it used to get called and I could then change the UI to show that it's no longer being edited.
This ONLY HAPPENS when the UIScrollView is set to dismiss the keyboard when dragged, and the user drags the UIScrollView.
If the user instead taps another UIView that can become a first responder e.g. a UITextField, then resignFirstResponder gets called.
Am I missing something that changed in iOS11 or have I hit a bug?

UITextField calls textFieldDidEndEditing when cleared but `text` property has data

Did anyone notice that UITextField calls textFieldDidEndEditing after clear button is pressed but text property still has old data ?
I'm not sure what code-sample I can provide here. I'm using storyboard if that matters.
For now I have to rely on taking data from all edit controls on main form's "Submit" button. But ideally I'd prefer to collect data in textFieldDidEndEditing handler.
Are there any better workarounds ?
I'm on iOS 6.
Update: Basically here is what I have on the form
UITextField and UiButton are on the form.
Keyboard dimissed by calling resignFirstResponder in handler of UITapGestureRecognizer
Steps to reproduce the issue:
Click on edit control. Enter some text.
Tap outside of text control.
textFieldDidEndEditing is called. Property .text has value I entered. All good.
Click on edit control again.
Click on clear button.
textFieldDidEndEditing is called again. But property .text still has value I just deleted !
Now as you see cursor blinking inside UITextField tap on Button on the form.
Keyboard is dismissed by textFieldDidEndEditing was never called.
I'll upload sample project on GitHub tomorrow.
I ran into the exact same problem. In my case, at least, it was due to having added a UITapGestureRecognizer to self.view (to allow for dismissing the keyboard if tapping outside of a UITextField) and setting cancelsTouchesInView=NO on the gesture recognizer. I had set that property in order to get hyperlinking working on a TTTAttributesLabel I have elsewhere in the View.
My workaround was to watch for keyboard show and hide notifications, and toggle that property accordingly:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShowNotification:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHideNotification:) name:UIKeyboardDidHideNotification object:nil];
(sign up for notifications)
- (void)keyboardDidShowNotification:(NSNotification*)notification
{
tapGestureRecognizer.cancelsTouchesInView = YES;
}
- (void)keyboardDidHideNotification:(NSNotification *)notification
{
tapGestureRecognizer.cancelsTouchesInView = NO;
}
(handle notifications)
The only problem, behavior-wise, is that the hyperlink still doesn't work when the keyboard is displayed: touching it will simply dismiss the keyboard, not forward the touch to the link handler. But I can live with that. After the keyboard is dismissed, the link works fine.
First check UITextFieldDelegate is assigned or not, then
implement the textFieldShouldClear delegate and write the code here clear your textField
To do this you have to set the clearButtonMode property,
yourTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
yourTextField.delegate = self;
Then implement the textFieldShouldClear delegate
.h file
#interface myViewController: UIViewController <UITextFieldDelegate>{
}
.m file
-(BOOL)textFieldShouldClear:(UITextField *)textField
yourTextFeild.text = #"";
return YES;
}
try here:
-(BOOL) textFieldShouldReturn:(UITextField*) textField

Understanding resignFirstResponder with UITextField

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".

How do I dismiss the iOS keyboard?

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];
}

UITextField lose focus event

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()
}

Resources