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
Esto me ayudó: 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()
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 aCGRectValue
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)
}