9

In my view controller I'm subscribed to UIKeyboardWillShowNotification:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

so in my keyboardWillShow: method I'm able to retrieve some info about the keyboard from the notification. But what I want is to get the reference to the actual text field which brings the keyboard up. I couldn't find how to do that in google and I suspect it might be impossible, but someone might know. If it is indeed impossible then I would like to know if there's a possibility to make it reverse way - to get the info about the keyboard by having the reference to the text field. Thanks

Andrey Chernukha
  • 21,488
  • 17
  • 97
  • 161
  • 2
    You should use `UITextField delegate` function `textFieldShouldBeginEditing:` this delegate function will get call when your keyboard appears, and save the UITextField reference from this function? – iphonic Aug 13 '15 at 07:11
  • Yes, I know that of course, but it is not convenient for me in current architecture. I'm going to use that approach as a last resort if i don't find anything else – Andrey Chernukha Aug 13 '15 at 07:13
  • I wish I could add +2 to @iphonic: only `textFieldShouldBeginEditing:` works. The `keyboardWillShow ` is flaky, and will not work with hardware keyboards (bluetooth, common on iPad) – SwiftArchitect Aug 13 '15 at 07:37
  • @iphonic is 100% correct. Thanks! – Lance Samaria Nov 18 '21 at 23:00

4 Answers4

14

Let me emphasize that @iphonic comment is the right way to go.

You should use UITextField delegate function textFieldShouldBeginEditing:

Anything short of that is a kludge: UIKeyboardWillShowNotification assumes the software keyboard will show up, with is a very dangerous assumption and is likely to fail in all sorts of situations, starting with but not limited to Bluetooth keyboards. Try cmd-K in Simulator.

Here is aforementioned kludge, inspired by Get the current first responder without using a private API

func keyboardWillShow() {
    let firstResponder = self.findFirstResponder(inView: self.view)
    println("keyboardWillShow for \(firstResponder)")
}

func findFirstResponder(inView view: UIView) -> UIView? {
    for subView in view.subviews as! [UIView] {
        if subView.isFirstResponder() {
            return subView
        }

        if let recursiveSubView = self.findFirstResponder(inView: subView) {
            return recursiveSubView
        }
    }

    return nil
}
Community
  • 1
  • 1
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
6

There is one manual way

if ([firstName isFirstResponder]) {
    // caused due to firstName
} else if ([lastName isFirstResponder]) {
    // caused due to lastName
}

Swift

if firstName.isFirstResponder { // caused due to firstName } 
else
if lastName.isFirstResponder { // caused due to lastName }
Fahim Parkar
  • 30,974
  • 45
  • 160
  • 276
3

The easiest (and almost only) way to do this happens to also be the best way (as @iphonic mentioned)

Implement the UITextFieldDelegate delegate method textFieldShouldBeginEditing:textField

This method will be called before any other event (including any keyboard notifications)

Store the UITextField that received this delegate call to be referenced when determining which field triggered this event.


What I also recommend doing is, if you are looking to determine which keyboard fired the current keyboard appearance, within this delegate method simply register for receiving keyboard notifications.

- (BOOL)textFieldShouldBeginEditing:(UITextView *)textView {

    [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

    return YES;

}

This way, you can be certain that when keyboardWillShow: is called, it was in fact triggered from this specific text field.

Of course, to make sure you keep track of your text fields correctly, stop listening when the text field stops editing.

- (void)textFieldDidEndEditing:(UITextView *)textView {

    [NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardWillShowNotification object:nil];

}
Will Von Ullrich
  • 2,129
  • 2
  • 15
  • 42
2

There is much better way to do this via did begin editing notifications of UITextField and UITextView:

UITextFieldTextDidBeginEditingNotification

and

UITextViewTextDidBeginEditingNotification

- (void)startListeningForKeyboardNotification {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(responderDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(responderDidBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil];
}

- (void)responderDidBeginEditing:(NSNotification *)notification {
    if ([notification.object isKindOfClass:[UITextField class]]) {
        UITextField *textField = notification.object;
        // Do something with text field
    } else if ([notification.object isKindOfClass:[UITextView class]]) {
        UITextView *textView = notification.object;
        // Do something with text view
    }
}
Vitalii Gozhenko
  • 9,220
  • 2
  • 48
  • 66