keyboardWillShow gets called for other app's keyboards

冷暖自知 提交于 2019-12-01 16:49:56

I suggest you to check if your textField is first responder in keyboardWillShown method. If it is not, just ignore the notification.

func keyboardWillShow(notification: NSNotification) {
    if !myTextField.isFirstResponder() {
        return
    }
    self.keyboardIsShowing = true
    if let info = notification.userInfo {
       self.keyboardFrame = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
       self.arrangeViewOffsetFromKeyboard()
    }
}

UPDATE: Instead of checking for the firstResponder, it is safer if you check UIApplication.shareApplication().applicationSate == .Active

iOS 9+ only:

NSNotification that comes from keyboard contains following:

UIKeyboardIsLocalUserInfoKey - The key for an NSNumber object containing a Boolean that identifies whether the keyboard belongs to the current app.

In my case i also do this (which is probably needed for OP too):

func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    return UIApplication.shared.applicationState == .active
}

This way keyboard won't hide when switching between applications.

Just check whether the app state is active will be fine:

- (void)handleKeyboardWillShowNotification:(NSNotification *)notifaction{
    if([UIApplication sharedApplication].applicationState != UIApplicationStateActive){
        return;
    }
    //your code below...
}

You thought almost right right: You have to remove the specific notifications in viewWillDisappear:

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)

    let notificationCenter = NSNotificationCenter.defaultCenter()
    notificationCenter.removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
    notificationCenter.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}

You can deregister the notification on UIApplicationDidEnterBackgroundNotification and register again in UIApplicationDidBecomeActiveNotification. I cannot sure that that kind of behaviour is intentional but definitely something unexpected for me too.

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationBecomeActive", name: UIApplicationDidBecomeActiveNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationDidEnterBackground", name: UIApplicationDidEnterBackgroundNotification, object: nil)
}

func applicationBecomeActive()
{
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

func applicationDidEnterBackground()
{
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
Ahmed Hamed

You can make sure that the view contains a first responder before doing any thing in keyboardWillShow. Using a UIView extension (or category) like this one -sorry couldn't find swift equivalent but you get the idea-, you can detect if any of the view's subviews is a first responder. I believe this should also work in situations like having 2 apps in the foreground at the same time on iOS 9.

I wasn't able to use the Application life Cycle methods but I was able to fix this problem for myself by checking if any of my textfields in the current view are firstResponder.

Updated With Code:

NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: UIResponder.keyboardWillShowNotification,object: nil)

@objc func keyboardWillShow(_ notification: Notification) {
    if storeNameTextField.isFirstResponder || methodTextField.isFirstResponder || amountTextField.isFirstResponder || dateTextField.isFirstResponder || categoryTextField.isFirstResponder {
        if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
            let keyboardRectangle = keyboardFrame.cgRectValue
            let keyboardHeight = keyboardRectangle.height
            self.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight - 22, right: 0)
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!