【问题标题】:UIKeyboardWillShow notification called twice on physical device but not in simulatorUIKeyboardWillShow 通知在物理设备上调用了两次,但在模拟器中没有
【发布时间】:2018-08-10 00:25:48
【问题描述】:

当调用键盘时,我将 UIView 向上移动,在模拟器中运行良好,但是当我在实际设备上运行代码时,无论出于何种原因,都会调用 UIKeyboardWillShow 通知两次。我没有使用任何自定义键盘。

在 viewDidLoad 方法中我调用了这个方法。

func registerKeyBoardNotifications(){
    NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillAppear(notification:)), name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: .UIKeyboardWillHide, object: nil)
}

然后在 viewWillDisappear 中移除这些观察者。

@objc func keyBoardWillAppear(notification: NSNotification){
    if let userInfo = notification.userInfo,
       let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue,
       let beginFrame = userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue,
       beginFrame.isEqual(to: endFrame) == false{
          let keyboardSize = endFrame.cgRectValue
          self.view.frame.origin.y -= keyboardSize.height - keyboardConstant
          signUpButton.isEnabled = false
    }
}

keyboardWillAppear 处理程序在物理设备上调用了两次,但在模拟器中调用了一次,过去 2 天都在试图解决这个问题。

Xcode 9.4.1 斯威夫特 4.1

【问题讨论】:

    标签: ios swift xcode


    【解决方案1】:

    这可能会发生,并且没有文档可以保证只有一个通知。

    所以你应该只在你的代码中处理它,而不是每次都减去键盘高度。更聪明的解决方案是根据键盘的结束帧计算您的视图帧。

    【讨论】:

    • 这在苹果端不会有问题吗?
    • 另外,如果您能提供一个代码示例说明您将如何做到这一点,我们将不胜感激。
    • 我不是在写你的代码:你应该根据键盘的结束帧计算你的视图的可见性,这样视图和键盘就不会重叠。您正在从视图的原点中多次减去键盘的高度。
    • 没关系,我想通了。见上面的答案。谢谢。
    【解决方案2】:

    正如您被告知的那样,正确的方法是问自己正确的问题。例如,是不是以前键盘没有遮住我的视野,但现在可以了?那是应该被视为“进入”的场合。

    我有一个实用函数,它可以根据通知的userInfo 字典和我们关注的视图边界来计算几何。如果键盘不在视图的范围内,现在它会在,它正在进入;如果它在视图的范围内,而现在不在,它正在退出。我们返回该信息,以及视图边界坐标中的键盘框架:

    enum KeyboardState {
        case unknown
        case entering
        case exiting
    }
    func keyboardState(for d:[AnyHashable:Any], in v:UIView?) 
        -> (KeyboardState, CGRect?) {
            var rold = d[UIResponder.keyboardFrameBeginUserInfoKey] as! CGRect
            var rnew = d[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
            var ks : KeyboardState = .unknown
            var newRect : CGRect? = nil
            if let v = v {
                let co = UIScreen.main.coordinateSpace
                rold = co.convert(rold, to:v)
                rnew = co.convert(rnew, to:v)
                newRect = rnew
                if !rold.intersects(v.bounds) && rnew.intersects(v.bounds) {
                    ks = .entering
                } 
                if rold.intersects(v.bounds) && !rnew.intersects(v.bounds) {
                    ks = .exiting
                }
            }
            return (ks, newRect)
    }
    

    当键盘出现时,我们检查它是否正在输入,并做出相应的反应:

    @objc func keyboardShow(_ n:Notification) {
        let d = n.userInfo!
        let (state, rnew) = keyboardState(for:d, in:myView)
        if state == .entering {
            // ...
        }
    }
    

    【讨论】:

      【解决方案3】:

      我似乎已经弄清楚为什么 UIkeyboardWillShow 通知会在物理设备上而不是模拟器上触发两次。当您设置某些文本输入特征时,它与键盘上方的键盘建议有关。任何导致键盘上方建议的文本输入特征都会导致通知触发两次而不是一次,我猜一次是针对键盘本身,一次是针对键盘上方的建议栏。 (在我的情况下,因为没有关于模拟器的建议,它在模拟器中触发了一次,但在设备上触发了两次,因为在真实设备上有建议)。这是一个奇怪的案例,似乎没有记录。

      解决这个问题的一种方法(我选择的路线)是通过将所有文本输入特征设置为默认值并将文本字段的内容类型设置为用户名来禁用所有建议。

      另一种解决方案是在调整您尝试移动的 UIView 的框架之前,在您的代码中考虑第二个 UIkeyboardWillShowNotifcation 通知。

      【讨论】:

      • 我建议您按照先前的答案建议在代码中正确处理此问题,因为在键盘之间切换时它会继续触发。简单地将 Text 特征更改为默认值只是一个绷带。
      猜你喜欢
      • 2021-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      • 2021-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多