为什么每次选择另一个TextField时都会调用UIKeyboardWillShowNotification?

onm*_*133 10 xcode notifications first-responder ios

我有一个项目,其中包含一个UIScrollView和许多UITextField内部.

我第一次选择a UITextField,UIKeyboardWillShowNotification被称为,这很好.但每当我选择新的UITextField(键盘仍在那里),UIKeyboardWillShowNotification再次调用!!!,这很奇怪.

我还设置了一个符号断点[UIResponder resignFirstResponder],我看到它UIKeyboardWillShowNotification被调用之前和之后!

另一件事是UIKeyboardWillHideNotification只有当我点击键盘上的"完成"按钮时才会调用它

我敢肯定,不调用任何resignFirstResponder,becomeFirstResponder,endEditing任何地方.(我的意思是不要错误地打电话)

什么可能导致这个问题?

这是堆栈跟踪 在此输入图像描述

onm*_*133 12

问题是我设置inputAccessoryViewUITextField,而这个原因UIKeyboardWillShowNotification,当新的被称为再次UITextField选择了

这篇文章在iOS上使用键盘解释了这一点

当我们将外部键盘连接到iPad时,会发生其他更改.在这种特殊情况下,通知行为取决于控件的inputAccessoryView属性,这是显示键盘的原因.

如果inputAccessoryView不存在或其高度等于0磅,则不会发送键盘通知.我的猜测是,这是因为在这种情况下,应用程序中不会发生视觉变化.否则,所有通知都按预期运行 - 这意味着在键盘显示或隐藏在正常(未取消停靠或拆分)状态的大多数情况下,它们将被发送.

每当UITextField选择new时,操作系统需要再次计算键盘的帧,并发布以下通知

UIKeyboardWillChangeFrameNotification
UIKeyboardWillShowNotification
UIKeyboardDidChangeFrameNotification
UIKeyboardDidShowNotification
Run Code Online (Sandbox Code Playgroud)

当TextField失去其第一个响应者状态时,这同样适用

请注意,使用相同的 View inputAccessoryViewUIKeyboardWillShowNotification仅导致调用一次


pau*_*lvs 8

要解决此问题,我使用以下代码取消UIKeyboardWillShowNotification回调,如果键盘的框架没有更改.

func keyboardWillShow(notification: NSNotification) {

    let beginFrame = notification.userInfo![UIKeyboardFrameBeginUserInfoKey]!.CGRectValue()
    let endFrame = notification.userInfo![UIKeyboardFrameEndUserInfoKey]!.CGRectValue()

    // Return early if the keyboard's frame isn't changing.
    guard CGRectEqualToRect(beginFrame, endFrame) == false else {
        return
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

对于Swift 3/4:

func keyboardWillShow(notification: Notification) {

    let userInfo = notification.userInfo!
    let beginFrameValue = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)!
    let beginFrame = beginFrameValue.cgRectValue
    let endFrameValue = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)!
    let endFrame = endFrameValue.cgRectValue

    if beginFrame.equalTo(endFrame) {
        return
    }

    // Do something with 'will show' event
    ...
}
Run Code Online (Sandbox Code Playgroud)


mat*_*att 5

总的来说,我发现很多事情都会导致虚假UIKeyboardWillShowUIKeyboardWillHide通知。我的解决方案是使用一个属性来跟踪键盘是否已经显示:

func keyboardShow(_ n:Notification) {
    if self.keyboardShowing {
        return
    }
    self.keyboardShowing = true
    // ... other stuff
}

func keyboardHide(_ n:Notification) {
    if !self.keyboardShowing {
        return
    }
    self.keyboardShowing = false
    // ... other stuff
}
Run Code Online (Sandbox Code Playgroud)

这些守卫准确地阻止了虚假通知,之后一切就都很好了。而且该keyboardShowing属性可能因其他原因而有用,因此无论如何它都是值得跟踪的。

  • @badhanganesh 是的,我不再使用这种方法。我使用更复杂的方法,如下所示:https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch10p522textFieldScrollView/ch23p805textFieldSliding/ViewController.swift (3认同)