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:
-
Cuando se abre el teclado del
sistema Apple
(en vertical)
- UIKeyboardWillShowNotification se envía con una altura de teclado de 224
-
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
-
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;
}];