iosswiftkeyboardfirst-responderinputaccessoryview

UIKeyboardDidShow triggers too often?


In order to display a text field right above the user's keyboard, I overrode inputAccessoryView in my custom view controller.
I also made sure that the view controller may become the first responder by overriding canBecomeFirstResponder (and returning true) and by calling self.becomeFirstResponder() in viewWillAppear().

Now, as I am displaying some messages as UICollectionViewCells in my view controller, I want to scroll down whenever the keyboard shows up. So I added a notification in viewDidLoad():

NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: Notification.Name.UIKeyboardDidShow, object: nil)

keyboardDidShow() then calls the scrolling function:

@objc private final func scrollToLastMessage() {
    // ('messages' holds all messages, one cell represents a message.)
    guard messages.count > 0 else { return }
    let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
    self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
}

Indeed, by setting breakpoints in Xcode, I found out that the function gets triggered after the keyboard has appeared. But additionally, it also triggers after I resigned the first responder (f.ex. by hitting the return key [I resign the first responder and return true in textFieldShouldReturn ]) and the keyboard has disappeared. Although I think that it shouldn't: as the Apple docs say:

Posted immediately after the display of the keyboard.

The notification also triggers when accessing the view controller, so after the main view has appeared and when clicking on a (customized) UICollectionViewCell (the cell does not have any editable content, only static labels or image views, so the keyboard shouldn't even appear).

To give some more information: I pretty much followed this tutorial on Youtube: https://www.youtube.com/watch?v=ky7YRh01by8


Solution

  • The UIKeyboardDidShow notification may be posted more often than you might expect, not just when it initially appears. For example, when the frame changes after it was already visible, UIKeyboardDidShow is posted.

    However you can know if the keyboard is truly visible by inspecting the keyboard's end frame from within the userInfo dictionary. This will tell you its size and position on screen, which you can then use to determine how best to react in your user interface.