【问题标题】:NSNotificationCenter Swift 3.0 on keyboard show and hideNSNotificationCenter Swift 3.0 上的键盘显示和隐藏
【发布时间】:2017-06-02 18:41:00
【问题描述】:

我正在尝试在键盘显示和消失时运行一个函数并具有以下代码:

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(ViewController.keyBoardUp(Notification :)), name:  NSNotification.Name.UIKeyboardWillShow, object: nil)

以及下面的函数keyBoardUp

func keyBoardUp( Notification: NSNotification){
    print("HELLO")
}

但是,当键盘显示时,该功能不会打印到控制台。非常感谢您的帮助

【问题讨论】:

  • 将选择器更改为#selector(ViewController.keyBoardUp(notification:)) 并将函数更改为func keyBoardUp( notification: Notification){ print("HELLO") }
  • 在 swift 3 中,您不应该在函数中遇到编译器错误吗?

标签: ios swift keyboard-events nsnotificationcenter


【解决方案1】:

斯威夫特 3:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: Notification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: Notification.Name.UIKeyboardWillHide, object: nil)

}

func keyboardWillShow(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        print("notification: Keyboard will show")
        if self.view.frame.origin.y == 0{
            self.view.frame.origin.y -= keyboardSize.height
        }
    }

}

func keyboardWillHide(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0 {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

斯威夫特 4.2.1:

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

@objc fileprivate func keyboardWillShow(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        // Do something with size
    }
}

@objc fileprivate func keyboardWillHide(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        // Do something with size
    }
}

Swift 4.2+

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

}

@objc func keyboardWillShow(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0{
            self.view.frame.origin.y -= keyboardSize.height
        }
    }

}

@objc func keyboardWillHide(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0 {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

【讨论】:

  • 此代码将失败,键盘处于活动状态,键入任何内容,不要退出并按下 iphone 的锁定按钮,然后稍后解锁您的 iphone,您的视图将不可见
  • 我通过硬编码keyboardSize.height来解决这个问题(因为我不想将整个视图移动到键盘的高度,因为它只是部分覆盖了预期的区域。所以而不是那部分你可以输入一个 Int
  • 使用 UIKeyboardFrameEndUserInfoKey 获得正确的高度,在 iPad 上有不同的键盘高度(带或不带硬件键盘) - 对高度进行硬编码会导致问题。
【解决方案2】:

斯威夫特 4.2+

@vandana's 答案已更新以反映 更改 到 Swift 4.2 中的原生通知。

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

}

@objc func keyboardWillShow(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }

}

@objc func keyboardWillHide(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0 {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

此外,您需要使用 UIKeyboardFrameEndUserInfoKey 来说明 iOS 11 引入的 safeAreaInset 更改。

【讨论】:

  • 是 UIResponder.keyboardWillHideNotification 通知名称
  • 我也需要函数上的@objc 关键字。
  • @RobEllis 是的,这些都是 Swift 4+ 所必需的。感谢您指出:)
  • 记得在 viewWillAppear 中添加你的观察者并在 viewWillDisappear 中移除它们
【解决方案3】:

中设置键盘通知观察器
override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardNotification(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
}

并在你的函数中处理它

func keyboardNotification(notification: NSNotification) {
  print("keyboard displayed!!")
}

希望这会对你有所帮助。

【讨论】:

    【解决方案4】:

    斯威夫特 4.X / 5

    我喜欢内联的、基于块的方法,它已经存在很长时间了!你可以阅读更多关于addObserver(...)here的参数。

    这种方法的一些优点是:

    • 您不需要使用@objc 关键字
    • 您在设置观察者的同一位置编写回调代码

    重要提示:在您设置的对象的deinit 中调用NotificationCenter.default.removeObserver(observer) 注册观察者(通常是视图控制器)。

    let center = NotificationCenter.default
    
    let keyboardWillShowObserver: NSObjectProtocol = center.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { (notification) in
        guard let value = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
        let height = value.cgRectValue.height
    
        // use the height of the keyboard to layout your UI so the prt currently in
        // foxus remains visible
    }
    
    let keyboardWillHideObserver: NSObjectProtocol = center.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: nil) { (notification) in
    
        // restore the layout of your UI before the keyboard has been shown
    }
    

    【讨论】:

      【解决方案5】:

      为 swift 更新:

      // MARK:- Kyeboard hide/show methods
      
      func keyboardWasShown(_ notification: Notification) {
          if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
              if self.view.frame.origin.y == 0{
                  self.view.frame.origin.y -= keyboardSize.height
              }
          }
      }
      
      func keyboardWillBeHidden(_ notification: Notification) {
          if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
              if self.view.frame.origin.y != 0{
                  self.view.frame.origin.y += keyboardSize.height
              }
          }
      }
      
      func registerForKeyboardNotifications(){
          //Adding notifies on keyboard appearing
          NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
      
          NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
      }
      
      func deregisterFromKeyboardNotifications(){
          //Removing notifies on keyboard appearing
          NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
          NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
      }
      
      func textFieldDidBeginEditing(_ textField: UITextField) {
          if textField == mEnterPasswordTextField || textField == mEnterConfirmPassword  {
                  animateViewMoving(up: true, moveValue: 120)
          }
      }
      
      func textFieldDidEndEditing(_ textField: UITextField) {
          if textField == mEnterPasswordTextField || textField == mEnterConfirmPassword  {
                  animateViewMoving(up: false, moveValue: 120)
          }
      }
      
      func animateViewMoving (up:Bool, moveValue :CGFloat){
          let movementDuration:TimeInterval = 0.3
          let movement:CGFloat = ( up ? -moveValue : moveValue)
          UIView.beginAnimations( "animateView", context: nil)
          UIView.setAnimationBeginsFromCurrentState(true)
          UIView.setAnimationDuration(movementDuration )
          self.view.frame = self.view.frame.offsetBy(dx: 0,  dy: movement)
          UIView.commitAnimations()
      }
      

      //在viewDidLoad()中

      self.registerForKeyboardNotifications()
      self.deregisterFromKeyboardNotifications()
      

      【讨论】:

        【解决方案6】:

        KeyBoard 将在 Swift 4 中使用 TxtField 显示和隐藏

        class ViewController: UIViewController {
        
        
        @IBOutlet weak var commentsTxt: UITextField!
        @IBOutlet weak var keyboardBottom: NSLayoutConstraint!
        
        override func viewWillAppear(_ animated: Bool) {
            IQKeyboardManager.shared.enable = false
            NotificationCenter.default.addObserver(
                self,
                selector: #selector(keyboardWillShow),
                name: UIResponder.keyboardWillShowNotification,
                object: nil
            )
            NotificationCenter.default.addObserver(
                self,
                selector: #selector(keyboarddidHide),
                name: UIResponder.keyboardWillHideNotification,
                object: nil
            )
        }
        
        @objc func keyboardWillShow(_ notification: Notification) {
            if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
                let keyboardRectangle = keyboardFrame.cgRectValue
                let keyboardHeight = keyboardRectangle.height
                self.keyboardBottom.constant = keyboardHeight - self.bottomLayoutGuide.length
                DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: {
                    let bottomOffset = CGPoint(x: 0, y: self.scrlView.contentSize.height - self.scrlView.bounds.size.height)
                    self.scrlView.setContentOffset(bottomOffset, animated: true)
                })
            }
        }
        @objc func keyboarddidHide(_ notification: Notification) {
            self.keyboardBottom.constant = 0
            
        }
        
           override func viewWillDisappear(_ animated: Bool) {
            IQKeyboardManager.shared.enable = true
             NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        

        }

        【讨论】:

          【解决方案7】:

          试试这个

           override func viewDidLoad()
              {
              super.viewDidLoad()
              NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
              NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
          }
          
           @objc func keyboardWillShow(notification: NSNotification) {
                if(messageCount > 0)
                {
                  tableView.scrollToRow(at: IndexPath(item:messageCount - 1, section: 0), at: .bottom, animated: true)
                }
          }
          
          @objc func keyboardWillHide(notification: NSNotification) {
              if(messageCount > 0)
              {
                  tableView.scrollToRow(at: IndexPath(item:0, section: 0), at: .top, animated: true)
              }
          }
          

          【讨论】:

            【解决方案8】:

            斯威夫特 4.2

            NotificationCenter.default.addObserver(self, selector: #selector(didReceiveKeyboardNotificationObserver(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(didReceiveKeyboardNotificationObserver(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
            
            @objc func didReceiveKeyboardNotificationObserver(_ notification: Notification) {
                let userInfo = notification.userInfo
                let keyboardBounds = (userInfo!["UIKeyboardBoundsUserInfoKey"] as! NSValue).cgRectValue
                let keyboardFrame = (userInfo!["UIKeyboardFrameEndUserInfoKey"] as! NSValue).cgRectValue
                let duration = userInfo!["UIKeyboardAnimationDurationUserInfoKey"] as! Double
                let curve = userInfo!["UIKeyboardAnimationCurveUserInfoKey"] as! Int
                let frameBegin = (userInfo!["UIKeyboardFrameBeginUserInfoKey"] as! NSValue).cgRectValue
                let centerBegin = (userInfo!["UIKeyboardCenterBeginUserInfoKey"] as! NSValue).cgPointValue
                let center = (userInfo!["UIKeyboardCenterEndUserInfoKey"] as! NSValue).cgPointValue
                let location = userInfo!["UIKeyboardIsLocalUserInfoKey"] as! Int
                println("keyboardBounds: \(keyboardBounds) \nkeyboardFrame: \(keyboardFrame) \nduration: \(duration) \ncurve: \(curve) \nframeBegin:\(frameBegin) \ncenterBegin:\(centerBegin)\ncenter:\(center)\nlocation:\(location)")
                switch notification.name {
                case UIResponder.keyboardWillShowNotification:
                // keyboardWillShowNotification
                case UIResponder.keyboardWillHideNotification:
                // keyboardWillHideNotification
                default:
                    break
                }
            }
            

            【讨论】:

              【解决方案9】:

              斯威夫特 4.2

              此版本适用于 iPhone 5 和 iPhone X。如果您在约束设置期间尊重安全区域,它会非常有效。

              override func viewDidLoad() {
                      super.viewDidLoad()
                      NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
                      NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
              }
              
              @objc func keyboardWillShow(notification: NSNotification) {
                      if let _ = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
                          self.view.frame.origin.y = self.navigationController!.navigationBar.frame.size.height + UIApplication.shared.statusBarFrame.size.height
                          if self.emailTextField.isFirstResponder {
                              self.view.frame.origin.y -= 100
                          } else if self.passwordTextField.isFirstResponder {
                              self.view.frame.origin.y -= 150
                          } else if self.passwordConfirmTextField.isFirstResponder {
                              self.view.frame.origin.y -= 200
                          }
                      }
              }
              
              @objc func keyboardWillHide(notification: NSNotification) {
                      if self.view.frame.origin.y != 0 {
                         self.view.frame.origin.y = self.navigationController!.navigationBar.frame.size.height + UIApplication.shared.statusBarFrame.size.height
                      }
              }
              

              【讨论】:

                【解决方案10】:

                斯威夫特 > 4.++

                您可以使用协议和协议扩展。 让我们创建 KeyboardListener 协议

                protocol KeyboardListener: class {
                   func registerKeyboardObserver()
                   func keyboardDidUpdate(keyboardHeight: CGFloat)
                   func removeObserver()
                }
                

                然后在 UIViewController 扩展中创建 @objc 函数

                extension UIViewController {
                @objc func adjustForKeyboard(notification: Notification) {
                    guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
                    
                    let keyboardScreenEndFrame = keyboardValue.cgRectValue
                    let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
                    
                    if notification.name == UIResponder.keyboardWillHideNotification {
                        if let keyboardLister = self as? KeyboardListener {
                            keyboardLister.keyboardDidUpdate(keyboardHeight: .zero)
                        }
                    } else {
                        if let keyboardLister = self as? KeyboardListener {
                            keyboardLister.keyboardDidUpdate(keyboardHeight: keyboardViewEndFrame.height - view.safeAreaInsets.bottom)
                        }
                    }
                }
                

                }

                然后,为默认实现使用键盘侦听器扩展

                extension KeyboardListener where Self: UIViewController {
                func registerKeyboardObserver() {
                    let notificationCenter = NotificationCenter.default
                    notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
                    notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
                }
                
                func removeObserver() {
                    NotificationCenter.default.removeObserver(self)
                }
                

                }

                最后,我们可以在 ViewController 类中使用它

                extension EditProfileVC: KeyboardListener {
                func keyboardDidUpdate(keyboardHeight: CGFloat) {
                    //update view when keyboard appear, 
                }
                

                }

                并从 viewwillAppear 调用 register 并从 deinit 调用 removeObserver

                 override func viewWillAppear(_ animated: Bool) {
                    super.viewWillAppear(animated)
                    registerKeyboardObserver()
                }
                
                deinit {
                   removeObserver()
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-04-13
                  • 2016-05-30
                  相关资源
                  最近更新 更多