在Swift中从userInfo获取键盘大小

我一直试图添加一些代码来移动我的视图,当键盘出现,但是,我有问题试图将Objective-C的例子转换成Swift。 我已经取得了一些进展,但我陷入了一个特定的路线。

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

如何向上移动UIViewController的内容,使用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)) 

如果有人能让我知道这行代码应该是什么,我应该设法自己找出其余的。

你的线路有一些问题

 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) // ... } 

对于更less的代码考虑看这个

这对我真的很有帮助。 你只需要在视图控制器中包含视图约束,并使用你添加的两个观察者。 然后,只需使用下面的方法(它应该在这里移动一个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() }) } } } 

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

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

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

 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) } 

在故事板里,设置底部约束。 创build这个约束的出口:

在这里输入图像说明

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

 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() } 

现在,只要键盘出现或消失,自动布局将会照顾到一切。

Swift 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 } 

Swift 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 } 

这帮助了我: 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() 

你可以用这一行代替你的行

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

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) } 

Swift 3.0

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

我添加了一个出口到我想要animation的视图的底部空间约束 ,并将其命名为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() } 

细节

xCode 8.2.1,swift 3

KeyboardNotifications

 import Foundation class KeyboardNotifications { fileprivate var _isEnabled: Bool fileprivate var notifications: [KeyboardNotificationsType] fileprivate 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(KeyboardNotifications.keyboardWillShow(notification:)) case .willHide: return #selector(KeyboardNotifications.keyboardWillHide(notification:)) case .didShow: return #selector(KeyboardNotifications.keyboardDidShow(notification:)) case .didHide: return #selector(KeyboardNotifications.keyboardDidHide(notification:)) } } var notificationName: NSNotification.Name { switch self { case .willShow: return .UIKeyboardWillShow case .willHide: return .UIKeyboardWillHide case .didShow: return .UIKeyboardDidShow case .didHide: return .UIKeyboardDidHide } } } } // MARK: - isEnabled extension KeyboardNotifications { private func addObserver(type: KeyboardNotificationsType) { NotificationCenter.default.addObserver(self, selector: type.selector, name: type.notificationName, object: nil) print("\(type.notificationName.rawValue) inited") } var isEnabled: Bool { set { if newValue { for notificaton in notifications { addObserver(type: notificaton) } } else { NotificationCenter.default.removeObserver(self) print("Keyboard notifications deinited") } _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) } } 

KeyboardNotificationsDelegate

 import Foundation @objc protocol KeyboardNotificationsDelegate { @objc optional func keyboardWillShow(notification: NSNotification) @objc optional func keyboardWillHide(notification: NSNotification) @objc optional func keyboardDidShow(notification: NSNotification) @objc optional func keyboardDidHide(notification: NSNotification) } 

用法

  class ViewController: UIViewController { private var keyboardNotifications: KeyboardNotifications! override func viewDidLoad() { super.viewDidLoad() ... keyboardNotifications = 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) { ... } // If you don't need this func you can remove it func keyboardWillHide(notification: NSNotification) { ... } // If you don't need this func you can remove it func keyboardDidShow(notification: NSNotification) { ... } // If you don't need this func you can remove it func keyboardDidHide(notification: NSNotification) { ... } } 

完整的示例

 import UIKit class ViewController: UIViewController { private var keyboardNotifications: KeyboardNotifications! private var textField = UITextField(frame: CGRect(x: 40, y: 40, width: 200, height: 30)) override func viewDidLoad() { super.viewDidLoad() view.addSubview(textField) // when you will tap on view (background) the keyboard will hide // read about view.disableKeybordWhenTapped here: http://stackoverflow.com/a/42187286/4488252 view.disableKeybordWhenTapped = true keyboardNotifications = 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") let userInfo = notification.userInfo as! [String: NSObject] let keyboardFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as! CGRect 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") } } 

结果

在这里输入图像说明

日志

在这里输入图像说明

对于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; }