3

Is it possible to redirect the becomeFirstResponder from self to a subview?

Here is my scenario.
I create a new UIWindow, let's call it secWin, object with a UINavigationController, let's call it navCon, as the rootViewController.
navCon has a custom UIViewController, let's call it cusViewCon, as rootViewController which contains only a single UITextField.
Now when i press a button in my main window, i call [secWin makeKeyAndVisible], which successfully shows the new window.
But now i want the UITextField to show the keyboard any time cusViewCon gets a becomeFirstResponder call, which is e.g. done by iOS by default when calling [secWin makeKeyAndVisible].

I tried to do all this by simply overwrite becomeFirstResponder in my cusViewCon class like this:

- (BOOL)becomeFirstResponder {
    [_myTextField becomeFirstResponder];

    return NO;
}

It is working, but i don't know if it is the correct way to do so, because in the documentation it says:

You can override this method in your custom responders to update your object's state or perform some action such as highlighting the selection. If you override this method, you must call super at some point in your implementation.

manuelwaldner
  • 551
  • 1
  • 5
  • 24
  • First of all, you should have only one window, unless you really need to do something special. Why do you need two windows? – meaning-matters Oct 25 '17 at 11:36
  • 1
    The second window is needed for a "lock screen", which should be above everything else. This lock screen was implemented as a modal view controller before, but raised many problems and we decided to change that and the window was our best solution. – manuelwaldner Oct 25 '17 at 12:27

3 Answers3

7

This method actually makes more sense when you code a bit for macOS where pretty much any view may become first responder. So don't worry to much about documentation.

Your procedure is on a correct track but I would do something like:

- (BOOL)becomeFirstResponder {
    BOOL willBecomeFirstResponder = [super becomeFirstResponder];
    if(willBecomeFirstResponder) {
        return YES; // This element is taking over the first responder so do nothing
    }
    else {
        [_myTextField becomeFirstResponder]; // This element may not become first responder at the moment so forward message to text field
        return NO;
    }
}

This way we ensure the execution of the superclass method still occurs. It should return false in your case (if not then also take a look into canBecomeFirstResponder method) so the text field should receive the message. If it does become first responder by design then it is best not to call it on your text field.

Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
  • Thank you. This helps a lot, the "you have to call the super implementation" gave me a lot of headache. But you answered all of my concerns about my implementation. – manuelwaldner Oct 25 '17 at 12:28
1

For those who also struggle with customisation of the responder chain in Swift, here is my take at the accepted answer. Might be useful for someone.

@discardableResult
override func becomeFirstResponder() -> Bool {
    if super.becomeFirstResponder() { return true }
    someView.becomeFirstResponder()
    return false
}
@discardableResult
override func resignFirstResponder() -> Bool {
    if super.resignFirstResponder() { return true }
    someView.resignFirstResponder()
    return false
}

someView in here is just your child view you are passing the event to. It can be UITextView, UITextField or any other UIResponder.

Witek Bobrowski
  • 3,749
  • 1
  • 20
  • 34
0

If you are using Swift, try this:

override func becomeFirstResponder() -> Bool {
    return super.becomeFirstResponder() || myTextField.becomeFirstResponder()
}
Isaiah Turner
  • 2,574
  • 1
  • 22
  • 35
  • this is wrong. the docs state that `becomeFirstResponder` should return "true if this object is now the first-responder or false if it is not.". However, your implementation will also return true if the subview becomes first responder (in which case `self` is not first responder, but the subview is) – lukas Aug 07 '20 at 15:55