【问题标题】:Getting keyboard size from userInfo in Swift从 Swift 中的 userInfo 获取键盘大小
【发布时间】:2014-10-16 13:01:53
【问题描述】:

我一直在尝试添加一些代码以在键盘出现时向上移动我的视图,但是,我在尝试将 Objective-C 示例转换为 Swift 时遇到了问题。我已经取得了一些进展,但我被困在一个特定的路线上。

这是我一直关注的两个教程/问题:

How to move content of UIViewController upwards as Keypad appears using Swift http://www.ioscreator.com/tutorials/move-view-when-keyboard-appears

这是我目前拥有的代码:

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

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
    UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    let frame = self.budgetEntryView.frame
    frame.origin.y = frame.origin.y - keyboardSize
    self.budgetEntryView.frame = frame
}

func keyboardWillHide(notification: NSNotification) {
    //
}

目前,我在这一行遇到错误:

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))

如果有人能让我知道这行代码应该是什么,我应该自己弄清楚其余的。

【问题讨论】:

    标签: swift uikeyboard


    【解决方案1】:

    你的线路有一些问题:

    var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
    
    • notification.userInfo 返回一个可选 字典[NSObject : AnyObject]?, 因此必须在访问其值之前对其进行解包。
    • Objective-C NSDictionary 映射到 Swift 原生字典,所以你必须 使用字典下标语法 (dict[key]) 来访问这些值。
    • 该值必须转换为NSValue,以便您可以调用CGRectValue

    所有这一切都可以通过可选赋值、可选链接和可选强制转换的组合来实现:

    if let userInfo = notification.userInfo {
       if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
           // ...
       } else {
           // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
       }
    } else {
       // no userInfo dictionary in notification
    }
    

    或一步到位:

    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
        // ...
    }
    

    Swift 3.0.1 (Xcode 8.1) 更新:

    if let userInfo = notification.userInfo {
        if let keyboardSize = userInfo[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
            let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
            // ...
        } else {
            // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
        }
    } else {
        // no userInfo dictionary in notification
    }
    

    或一步到位:

    if let keyboardSize = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
        // ...
    }
    

    Swift 5 (Xcode 11.6) 更新:

     guard let userInfo = notification.userInfo,
                  let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
    

    我建议使用 keyboardFrameEndUserInfoKey 而不是 keyboardFrameBeginUserInfoKey,因为在旧 iOS 设备上首次显示后,键盘会更改初始渲染高度。

    【讨论】:

    • @MartinR 很抱歉我评论错了帖子:) 抱歉
    • 您好,我正在尝试通过通知获取键盘大小,但无法正常工作。我在 viewDidload 中添加了观察者(也尝试了 viewWillAppear) NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil) 但是没有调用该方法。我在真机和模拟器上试了一下。有什么建议吗?非常感谢。
    • “一步”答案中有 cgRectValue,但应该是 CGRectValue
    • @krotov 答案的第一部分适用于 Swift 2,第二部分适用于 Swift 3。该属性在这些版本之间已重命名。
    • 我认为在键盘框架发生变化时使用 UIKeyboardFrameEndUserInfoKey 而不是 UIKeyboardFrameBeginUserInfoKey 更好(在 iOS 9 或更高版本中启用预测或切换到表情符号键盘)
    【解决方案2】:

    对于更少的代码,请考虑查看THIS

    这对我真的很有帮助。 您只需在视图控制器中包含视图约束并使用您添加的两个观察者。然后就用下面的方法(这里假设你移动了一个tableView)

    func keyboardWillShow(sender: NSNotification) {
            if let userInfo = sender.userInfo {
                if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().size.height {
                    tableViewBottomConstraint.constant = keyboardHeight
                    UIView.animateWithDuration(0.25, animations: { () -> Void in
                        self.view.layoutIfNeeded()
                    })
                }
            }
        }
    

    func keyboardWillHide(sender: NSNotification) {
    if let userInfo = sender.userInfo {
      if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().size.height {
        tableViewBottomConstraint.constant = 0.0
        UIView.animateWithDuration(0.25, animations: { () -> Void in self.view.layoutIfNeeded() })
      }
    } }
    

    【讨论】:

    • 直到我在其他地方看到它才得到这个答案,我很清楚 tableViewBottomConstraint 是 Xib 的一个出口。然后很明显这是完美的答案! (如果您使用的是自动布局)
    • @JorisvanLiempd 是的,我正在使用自动布局。很好,对你有帮助。
    • 看来动画是免费的,没有动画块。在这个答案中,无论如何都不遵循键盘曲线和持续时间。
    【解决方案3】:

    如果您使用故事板,而不是操纵视图本身,您可以利用自动布局。

    (这是尼古拉斯的答案的清理版本)

    设置通知中心,通知您键盘的出现和消失:

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
    
    }
    

    并确保在不再需要观察者时将其移除:

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
    }
    

    在情节提要中,设置底部约束。创建该约束的出口:

    并在键盘显示或隐藏时设置约束的常量属性:

    func keyboardWillShow(notification: NSNotification) {
        guard let keyboardHeight = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue.size.height else {
            return
        }
        nameOfOutlet.constant = keyboardHeight
        view.layoutIfNeeded()
    }
    
    func keyboardWillHide(notification: NSNotification) {
        nameOfOutlet.constant = 0.0
        view.layoutIfNeeded()
    }
    

    现在,无论何时键盘出现或消失,自动布局都会处理所有事情。

    【讨论】:

      【解决方案4】:

      斯威夫特 2

      func keyboardWasShown(notification:NSNotification) {
              guard let info:[NSObject:AnyObject] = notification.userInfo,
                  let keyboardSize:CGSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size else { return }
      
              let insets:UIEdgeInsets = UIEdgeInsetsMake(self.scrollView.contentInset.top, 0.0, keyboardSize.height, 0.0)
      
              self.scrollView.contentInset = insets
              self.scrollView.scrollIndicatorInsets = insets
          }
      

      斯威夫特 3

      func keyboardWasShown(notification:NSNotification) {
          guard let info:[AnyHashable:Any] = notification.userInfo,
              let keyboardSize:CGSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size else { return }
      
          let insets:UIEdgeInsets = UIEdgeInsets(top: self.scrollView.contentInset.top, left: 0.0, bottom: keyboardSize.height, right: 0.0)
      
          self.scrollView.contentInset = insets
          self.scrollView.scrollIndicatorInsets = insets
      }
      

      【讨论】:

      • 谢谢,对我帮助很大!
      【解决方案5】:

      这对我有帮助:https://developer.apple.com/library/ios/samplecode/UICatalog/Listings/Swift_UICatalog_TextViewController_swift.html

      let userInfo = notification.userInfo!
      
      let animationDuration: NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as NSNumber).doubleValue
      let keyboardScreenBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
      let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
      

      【讨论】:

        【解决方案6】:

        您可以将这一行用作您的行

        var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size
        

        【讨论】:

        • 从该字典中强制展开键盘框架是不安全的。不可能在那里。
        【解决方案7】:

        Swift 3:更新

        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        
        }
        
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
        }
        

        【讨论】:

          【解决方案8】:

          Swift - 来自keyboardWillShowNotification的键盘高度

          您可以使用来自键盘 Will/did Show/hide Notifications 的数据将约束或任何其他值扩大或缩小到键盘的大小。

          带有布局约束

          此最小代码注册通知键盘将显示并根据其大小更新约束。

          @IBOutlet weak var keyboardConstraint: NSLayoutConstraint!
          let keyboardConstraintMargin:CGFloat = 20
          
          override func viewDidLoad() {
              super.viewDidLoad()
              NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { (notification) in
                  if let keyboardSize = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect {
                      self.keyboardConstraint.constant = keyboardSize.height + self.keyboardConstraintMargin
                  }
              }
              NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidHideNotification, object: nil, queue: nil) { (notification) in
                  self.keyboardConstraint.constant = self.keyboardConstraintMargin
              }
          }
          

          带有滚动视图

          以同样的方式,这会根据键盘的大小更新滚动视图的内容插图。

          @IBOutlet weak var scrollView: UIScrollView!
          
          override func viewDidLoad() {
            super.viewDidLoad()
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { (notification) in
              if let keyboardSize = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect {
                let insets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
                self.scrollView.contentInset = insets
                self.scrollView.scrollIndicatorInsets = insets
              }
            }
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidHideNotification, object: nil, queue: nil) { (notification) in
              let insets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
              self.scrollView.contentInset = insets
              self.scrollView.scrollIndicatorInsets = insets
            }
          }
          

          【讨论】:

            【解决方案9】:

            详情

            • Xcode 版本 11.1 (11A1027)、iOS 13、Swift 5

            解决方案

            import UIKit
            
            protocol KeyboardNotificationsDelegate: class {
                func keyboardWillShow(notification: NSNotification)
                func keyboardWillHide(notification: NSNotification)
                func keyboardDidShow(notification: NSNotification)
                func keyboardDidHide(notification: NSNotification)
            }
            
            extension KeyboardNotificationsDelegate {
                func keyboardWillShow(notification: NSNotification) {}
                func keyboardWillHide(notification: NSNotification) {}
                func keyboardDidShow(notification: NSNotification) {}
                func keyboardDidHide(notification: NSNotification) {}
            }
            
            class KeyboardNotifications {
            
                fileprivate var _isEnabled: Bool
                fileprivate var notifications: [KeyboardNotificationsType]
                fileprivate weak var delegate: KeyboardNotificationsDelegate?
            
                init(notifications: [KeyboardNotificationsType], delegate: KeyboardNotificationsDelegate) {
                    _isEnabled = false
                    self.notifications = notifications
                    self.delegate = delegate
                }
            
                deinit { if isEnabled { isEnabled = false } }
            }
            
            // MARK: - enums
            
            extension KeyboardNotifications {
            
                enum KeyboardNotificationsType {
                    case willShow, willHide, didShow, didHide
            
                    var selector: Selector {
                        switch self {
                            case .willShow: return #selector(keyboardWillShow(notification:))
                            case .willHide: return #selector(keyboardWillHide(notification:))
                            case .didShow: return #selector(keyboardDidShow(notification:))
                            case .didHide: return #selector(keyboardDidHide(notification:))
                        }
                    }
            
                    var notificationName: NSNotification.Name {
                        switch self {
                            case .willShow: return UIResponder.keyboardWillShowNotification
                            case .willHide: return UIResponder.keyboardWillHideNotification
                            case .didShow: return UIResponder.keyboardDidShowNotification
                            case .didHide: return UIResponder.keyboardDidHideNotification
                        }
                    }
                }
            }
            
            // MARK: - isEnabled
            
            extension KeyboardNotifications {
            
                private func addObserver(type: KeyboardNotificationsType) {
                    NotificationCenter.default.addObserver(self, selector: type.selector, name: type.notificationName, object: nil)
                }
            
                var isEnabled: Bool {
                    set {
                        if newValue {
                            for notificaton in notifications { addObserver(type: notificaton) }
                        } else {
                            NotificationCenter.default.removeObserver(self)
                        }
                        _isEnabled = newValue
                    }
            
                    get { return _isEnabled }
                }
            
            }
            
            // MARK: - Notification functions
            
            extension KeyboardNotifications {
            
                @objc func keyboardWillShow(notification: NSNotification) {
                    delegate?.keyboardWillShow(notification: notification)
                }
            
                @objc func keyboardWillHide(notification: NSNotification) {
                    delegate?.keyboardWillHide(notification: notification)
                }
            
                @objc func keyboardDidShow(notification: NSNotification) {
                    delegate?.keyboardDidShow(notification: notification)
                }
            
                @objc func keyboardDidHide(notification: NSNotification) {
                    delegate?.keyboardDidHide(notification: notification)
                }
            }
            

            用法

            class ViewController: UIViewController {
            
                private lazy var keyboardNotifications: KeyboardNotifications! = {
                    return KeyboardNotifications(notifications: [.willShow, .willHide, .didShow, .didHide], delegate: self)
                }()
            
                override func viewWillAppear(_ animated: Bool) {
                    super.viewWillAppear(animated)
                    keyboardNotifications.isEnabled = true
                }
            
                override func viewWillDisappear(_ animated: Bool) {
                    super.viewWillDisappear(animated)
                    keyboardNotifications.isEnabled = false
                }
            }
            
            extension ViewController: KeyboardNotificationsDelegate {
            
                // If you don't need this func you can remove it
                func keyboardWillShow(notification: NSNotification) {
                    print("keyboardWillShow")
                    guard   let userInfo = notification.userInfo as? [String: NSObject],
                            let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
                    print("keyboardFrame: \(keyboardFrame)")
                }
            
                // If you don't need this func you can remove it
                func keyboardWillHide(notification: NSNotification) { print("keyboardWillHide") }
            
                // If you don't need this func you can remove it
                func keyboardDidShow(notification: NSNotification) { print("keyboardDidShow") }
            
                // If you don't need this func you can remove it
                func keyboardDidHide(notification: NSNotification) { print("keyboardDidHide") }
            }
            

            完整样本

            import UIKit
            
            class ViewController: UIViewController {
            
                private lazy var keyboardNotifications: KeyboardNotifications! = {
                    return KeyboardNotifications(notifications: [.willShow, .willHide, .didShow, .didHide], delegate: self)
                }()
            
                override func viewDidLoad() {
                    super.viewDidLoad()
            
                    let textField = UITextField(frame: CGRect(x: 40, y: 40, width: 200, height: 30))
                    textField.borderStyle = .roundedRect
                    view.addSubview(textField)
            
                    let gesture = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:)))
                    view.addGestureRecognizer(gesture)
                }
            
                override func viewWillAppear(_ animated: Bool) {
                    super.viewWillAppear(animated)
                    keyboardNotifications.isEnabled = true
                }
            
                override func viewWillDisappear(_ animated: Bool) {
                    super.viewWillDisappear(animated)
                    keyboardNotifications.isEnabled = false
                }
            }
            
             extension ViewController: KeyboardNotificationsDelegate {
            
                // If you don't need this func you can remove it
                func keyboardWillShow(notification: NSNotification) {
                    print("keyboardWillShow")
                    guard   let userInfo = notification.userInfo as? [String: NSObject],
                            let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
                    print("keyboardFrame: \(keyboardFrame)")
                }
            
                // If you don't need this func you can remove it
                func keyboardWillHide(notification: NSNotification) { print("keyboardWillHide") }
            
                // If you don't need this func you can remove it
                func keyboardDidShow(notification: NSNotification) { print("keyboardDidShow") }
            
                // If you don't need this func you can remove it
                func keyboardDidHide(notification: NSNotification) { print("keyboardDidHide") }
            }
            

            结果

            日志

            【讨论】:

              【解决方案10】:

              Swift 3.0

              下面是一个检索键盘大小并使用它为向上的视图设置动画的示例。在我的情况下,当用户开始输入时,我将包含我的 UITextFields 的 UIView 向上移动,这样他们就可以完成表单并仍然在底部看到提交按钮。

              我在想要动画的视图的底部空间约束中添加了一个出口,并将其命名为myViewsBottomSpaceConstraint

              @IBOutlet weak var myViewsBottomSpaceConstraint: NSLayoutConstraint!
              

              然后我将以下代码添加到我的 swift 类中:

              override func viewWillAppear(_ animated: Bool) {
                  super.viewWillAppear(animated)
                  NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
                  NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
              
              }
              
              override func viewWillDisappear(_ animated: Bool) {
                  super.viewWillDisappear(animated)
                  NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
                  NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
              }
              
              func keyboardWillShow(notification: NSNotification) {
              
                  let userInfo = notification.userInfo as! [String: NSObject] as NSDictionary
                  let keyboardFrame = userInfo.value(forKey: UIKeyboardFrameEndUserInfoKey) as! CGRect
                  let keyboardHeight = keyboardFrame.height
                  myViewsBottomSpaceConstraint.constant = keyboardHeight
                  view.layoutIfNeeded()
              }
              
              func keyboardWillHide(notification: NSNotification) {
                  myViewsBottomSpaceConstraint.constant = 0.0
                  view.layoutIfNeeded()
              }
              

              【讨论】:

                【解决方案11】:

                对于 xamarin,您可以使用 c#6

                private void KeyboardWillChangeFrame(NSNotification notification)
                {
                        var keyboardSize = notification.UserInfo.ValueForKey(UIKeyboard.FrameEndUserInfoKey) as NSValue;
                        if (keyboardSize != null)
                        {
                            var rect= keyboardSize.CGRectValue;
                            //do your stuff here
                        }
                }
                

                c#7

                  private void KeyboardWillChangeFrame(NSNotification notification)
                   {
                       if (!(notification.UserInfo.ValueForKey(UIKeyboard.FrameEndUserInfoKey) is NSValue keyboardSize)) return;
                       var rect= keyboardSize.CGRectValue;
                   }
                

                【讨论】:

                  【解决方案12】:

                  Swift 4.2 中,您可以使用 UIResponder.keyboardFrameEndUserInfoKey

                  guard let userInfo = notification.userInfo , let keyboardFrame:CGRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect  else { return  }```
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2015-06-04
                    • 2011-08-03
                    • 2013-04-17
                    • 2016-07-02
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-10-17
                    相关资源
                    最近更新 更多