swift uikeyboard

Obtener el tamaño del teclado desde userInfo en Swift



uikeyboard (10)

He intentado agregar un código para mover mi vista cuando aparece el teclado, sin embargo, tengo problemas al intentar traducir los ejemplos de Objective-C a Swift. He progresado un poco, pero estoy atrapado en una línea en particular.

Estos son los dos tutoriales / preguntas que he estado siguiendo:

Cómo mover el contenido de UIViewController hacia arriba cuando aparece el teclado con Swift http://www.ioscreator.com/tutorials/move-view-when-keyboard-appears

Aquí está el código que tengo actualmente:

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

Por el momento, estoy recibiendo un error en esta línea:

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

Si alguien pudiera decirme qué debería ser esta línea de código, debería resolver el resto yo mismo.


Detalles

xCode 8.2.1, swift 3

Código

TecladoNotificaciones

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

Uso

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

Muestra completa

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

Resultado

Iniciar sesión



Hay algunos problemas en tu línea

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

  • notification.userInfo devuelve un diccionario opcional [NSObject : AnyObject]? , entonces debe ser desenvuelto antes de acceder a sus valores.
  • El NSDictionary Objective-C se asigna a un diccionario nativo Swift, por lo que debe usar la sintaxis del subíndice del diccionario ( dict[key] ) para acceder a los valores.
  • El valor se debe convertir a NSValue para que pueda llamar a CGRectValue en él.

Todo esto se puede lograr con una combinación de asignación opcional, encadenamiento opcional y moldes opcionales:

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 }

o en un solo paso:

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

Actualización para 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 }

o en un solo paso:

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


Para menos código, considera mirar THIS

Fue realmente útil para mí. Solo tiene que incluir la restricción de vista en el controlador de vista y usar los dos observadores que agregó. Entonces solo usa los siguientes métodos (se supone que aquí mueves un 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() }) } } }

y

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


Para xamarin, puedes usar 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; }


Puedes usar esta línea para tu línea

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


Si está utilizando el guión gráfico, en lugar de manipular la vista en sí, puede aprovechar el diseño automático.

(Esta es una versión limpia de la Respuesta de Nicholas)

Configure el centro de notificaciones para notificarle la aparición y desaparición del teclado:

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

Y asegúrate de eliminar a los observadores cuando ya no los necesites:

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

Dentro del guión gráfico, establece la restricción inferior. Crea una salida de esa restricción:

y establece la propiedad constante de la restricción cuando el teclado se muestra u oculta:

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

Ahora, cada vez que el teclado aparece o desaparece, el diseño automático se encargará de todo.


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 }


Swift 3.0

Aquí hay un ejemplo de cómo recuperar el tamaño del teclado y usarlo para animar una vista hacia arriba. En mi caso, estoy moviendo una UIView que contiene mis UITextFields hacia arriba cuando un usuario comienza a escribir para que puedan completar un formulario y aún así ver el botón de enviar en la parte inferior.

Agregué una salida a la restricción de espacio inferior de la vista que quería animar y la myViewsBottomSpaceConstraint :

@IBOutlet weak var myViewsBottomSpaceConstraint: NSLayoutConstraint!

Luego agregué el siguiente código a mi clase rápida:

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


Swift 3: ACTUALIZAR

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