ios objective-c cocoa-touch keyboard ios8

no se puede obtener el valor correcto de la altura del teclado en iOS8



objective-c cocoa-touch (10)

Con la introducción de teclados personalizados en iOS, este problema se vuelve un poco más complejo.

En resumen, las implementaciones de teclado personalizadas pueden llamar a UIKeyboardWillShowNotification varias veces:

  1. Cuando se abre el teclado del sistema Apple (en vertical)
    • UIKeyboardWillShowNotification se envía con una altura de teclado de 224
  2. Cuando se abre el teclado Swype (en vertical):
    • UIKeyboardWillShowNotification se envía con una altura de teclado de 0
    • UIKeyboardWillShowNotification se envía con una altura de teclado de 216
    • UIKeyboardWillShowNotification se envía con una altura de teclado de 256
  3. Cuando se abre el teclado SwiftKey (en vertical):
    • UIKeyboardWillShowNotification se envía con una altura de teclado de 0
    • UIKeyboardWillShowNotification se envía con una altura de teclado de 216
    • UIKeyboardWillShowNotification se envía con una altura de teclado de 259

Para manejar estos escenarios correctamente en una línea de código, debe:

Registre observadores contra las notificaciones UIKeyboardWillShowNotification y UIKeyboardWillHideNotification :

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

Cree una variable global para rastrear la altura actual del teclado:

CGFloat _currentKeyboardHeight = 0.0f;

Implemente keyboardWillShow para reaccionar al cambio actual en la altura del teclado:

- (void)keyboardWillShow:(NSNotification*)notification { NSDictionary *info = [notification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; CGFloat deltaHeight = kbSize.height - _currentKeyboardHeight; // Write code to adjust views accordingly using deltaHeight _currentKeyboardHeight = kbSize.height; }

NOTA: es posible que desee animar el desplazamiento de las vistas. El diccionario de información contiene un valor tecleado por UIKeyboardAnimationDurationUserInfoKey . Este valor se puede usar para animar sus cambios a la misma velocidad que el teclado que se muestra.

Implemente keyboardWillHide en el reset _currentKeyboardHeight y reaccione al descarte del teclado:

- (void)keyboardWillHide:(NSNotification*)notification { NSDictionary *info = [notification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; // Write code to adjust views accordingly using kbSize.height _currentKeyboardHeight = 0.0f; }

Estaba usando este código para determinar cuál es el tamaño del teclado:

- (void)keyboardWillChange:(NSNotification *)notification { NSDictionary* keyboardInfo = [notification userInfo]; NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey]; CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue]; }

Estoy ejecutando esto en el simulador.

El problema es que desde iOS 8 esto no dará el valor correcto, si las sugerencias del teclado están arriba o si las presiono hacia abajo obtengo valores diferentes (no correctos).

¿Cómo puedo obtener el tamaño exacto del teclado, incluidas las sugerencias de teclado?


En Swift, no en una línea ...

self.keyboardDidShowObserver = NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardDidShowNotification, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: { (notification) in if let userInfo = notification.userInfo, let keyboardFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue { let keyboardRect = keyboardFrameValue.CGRectValue() // keyboardRect.height gives the height of the keyboard // your additional code here... } })


Hago extension para UIViewController

extension UIViewController { func keyboardWillChangeFrameNotification(notification: NSNotification, scrollBottomConstant: NSLayoutConstraint) { let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber let keyboardBeginFrame = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue() let keyboardEndFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue() let screenHeight = UIScreen.mainScreen().bounds.height let isBeginOrEnd = keyboardBeginFrame.origin.y == screenHeight || keyboardEndFrame.origin.y == screenHeight let heightOffset = keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y - (isBeginOrEnd ? bottomLayoutGuide.length : 0) UIView.animateWithDuration(duration.doubleValue, delay: 0, options: UIViewAnimationOptions(rawValue: UInt(curve.integerValue << 16)), animations: { () in scrollBottomConstant.constant = scrollBottomConstant.constant + heightOffset self.view.layoutIfNeeded() }, completion: nil ) } }

Puedes usar así:

override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChangeFrameNotification:", name: UIKeyboardWillChangeFrameNotification, object: nil) } ... deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } func keyboardWillChangeFrameNotification(notification: NSNotification) { self.keyboardWillChangeFrameNotification(notification, scrollBottomConstant: inputContainerBottom) // Write more to here if you want. }


Hay momentos en que los desarrolladores necesitan conocer la altura del teclado antes de que se muestre realmente, lo que les permite diseñar previamente la interfaz de manera adecuada.

Si ese es el caso, aquí hay una especificación inclusiva:

Esto incluye la barra de tipo rápido en la parte superior, ya que está activada de forma predeterminada en todas las versiones actuales de iOS.

Aquí está la configuración de notificación rápida 3 que usé para probar esto, si alguien lo necesita:

override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil) } func keyboardWillShow(notification: NSNotification) { guard let keyboardSize = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return } print("/(keyboardSize)") }


La solución similar a la de dgangsta''s escrita en Swift 2.0:

override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil) } deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } func keyboardWillShow(notification: NSNotification) { guard let kbSizeValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return } guard let kbDurationNumber = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber else { return } animateToKeyboardHeight(kbSizeValue.CGRectValue().height, duration: kbDurationNumber.doubleValue) } func keyboardWillHide(notification: NSNotification) { guard let kbDurationNumber = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber else { return } animateToKeyboardHeight(0, duration: kbDurationNumber.doubleValue) } func animateToKeyboardHeight(kbHeight: CGFloat, duration: Double) { // your custom code here }


Noté un problema al cambiar entre el teclado predeterminado y un teclado personalizado ( UIPickerView ): el teclado personalizado mostraría una altura de 253 en lugar de 162, después de cambiar desde el teclado predeterminado.

Lo que funcionó en este caso fue establecer autocorrectionType = UITextAutocorrectionTypeNo; para el campo de entrada con el teclado personalizado.

El problema solo ocurrió en iOS 8 (probado solo en el simulador). No ocurre en iOS 9 (simulador o dispositivo).


Solo una cuerda para swift:

let keyboardSize = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size

UIKeyboardFrameEndUserInfoKey siempre almacena NSValue , por lo que no es necesario verificarlo.


También tuve este problema, hasta que encontré este artículo de :

Convertir UIKeyboardFrameEndUserInfoKey

Esto le muestra cómo usar la función convertRect , para convertir el tamaño del teclado en algo utilizable, pero en la orientación de la pantalla.

NSDictionary* d = [notification userInfo]; CGRect r = [d[UIKeyboardFrameEndUserInfoKey] CGRectValue]; r = [myView convertRect:r fromView:nil];

Anteriormente, tenía una aplicación para iPad que usaba UIKeyboardFrameEndUserInfoKey pero no usaba convertRect , y funcionó bien.

Pero con iOS 8, ya no funcionaba correctamente. De repente, informaría que mi teclado, que se ejecuta en un iPad en modo horizontal, tenía 1024 píxeles de alto .

Así que ahora, con iOS 8, es esencial que use esta función convertRect .


Utilizar

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];


[notificationCenter addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) { float keyboardHeight = [[note.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; }];