impossible d'obtenir la valeur correcte de la hauteur du clavier dans iOS8

83

J'utilisais ce code pour déterminer quelle est la taille du clavier:

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

}

J'exécute ceci dans le simulateur.

Le problème est que depuis iOS 8, cela ne donnera pas la valeur correcte, si les suggestions de clavier sont en hausse ou si je les pousse vers le bas, j'obtiens des valeurs différentes (incorrectes).

Comment puis-je obtenir la taille exacte du clavier, y compris les suggestions de clavier?

Eli Braginskiy
la source
Cela peut aider si vous convertissez keyboardFrameBeginRecten coordonnées locales.
rmaddy
@rmaddy ça n'a pas vraiment d'importance, je n'ai besoin que de la hauteur.
Eli Braginskiy
Ce qui pourrait être faux selon l'orientation. Bien que cela ne soit plus un problème sous iOS 8. Essayez-le et voyez si cela fait une différence.
rmaddy
@rmaddy Je l'ai essayé mais malheureusement cela n'a pas aidé
Eli Braginskiy

Réponses:

98

Utilisation

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
souvickcse
la source
Très bonne réponse. Merci. Comment avez-vous trouvé que vous deviez utiliser cette clé? @souvickcse
Julian Osorio
6
CGRect keyboardFrame = [keyboardFrameBegin CGRectValue];
Awesomeness
12
Cela
Merci @trycatchfinally
souvickcse
1
appris une leçon aujourd'hui. Il y a une grande différence entre UIKeyboardFrameEndUserInfoKey et UIKeyboardFrameBeginUserInfoKey. Merci @souvickcse
jejernig
120

Avec l'introduction de claviers personnalisés dans iOS, ce problème devient un peu plus complexe.

En bref, le UIKeyboardWillShowNotification peut être appelé plusieurs fois par des implémentations de clavier personnalisées:

  1. Lorsque le clavier système Apple est ouvert (en portrait)
    • UIKeyboardWillShowNotification est envoyée avec une hauteur de clavier de 224
  2. Lorsque le clavier Swype est ouvert (en portrait):
    • UIKeyboardWillShowNotification est envoyée avec une hauteur de clavier de 0
    • UIKeyboardWillShowNotification est envoyée avec une hauteur de clavier de 216
    • UIKeyboardWillShowNotification est envoyée avec une hauteur de clavier de 256
  3. Lorsque le clavier SwiftKey est ouvert (en portrait):
    • UIKeyboardWillShowNotification est envoyée avec une hauteur de clavier de 0
    • UIKeyboardWillShowNotification est envoyée avec une hauteur de clavier de 216
    • UIKeyboardWillShowNotification est envoyée avec une hauteur de clavier de 259

Pour gérer correctement ces scénarios dans une seule ligne de code, vous devez:

Enregistrez les observateurs contre les notifications UIKeyboardWillShowNotification et UIKeyboardWillHideNotification :

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

Créez une variable globale pour suivre la hauteur actuelle du clavier:

CGFloat _currentKeyboardHeight = 0.0f;

Implémentez keyboardWillShow pour réagir au changement actuel de la hauteur du clavier:

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

REMARQUE: vous souhaiterez peut-être animer le décalage des vues. Le dictionnaire d' informations contient une valeur indexée par UIKeyboardAnimationDurationUserInfoKey . Cette valeur peut être utilisée pour animer vos modifications à la même vitesse que le clavier affiché.

Implémentez keyboardWillHide à la réinitialisation _currentKeyboardHeight et réagissez au renvoi du clavier:

- (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;
}
dgangsta
la source
dgangsta, votre recherche est intéressante, mais le problème de la question est simplement d'obtenir FrameBegin au lieu des propriétés FrameEnd. Selon votre réponse, aviez-vous envisagé d'utiliser l'indicateur UIViewAnimationOptionBeginFromCurrentState pour la méthode d'affichage des animations au lieu des deltas?
MikeR
Au lieu de 259 pour la hauteur SwiftKey (v 1.2.3), j'ai obtenu 271 dans iPhone6 ​​+ avec iOS8.1.3.
Hemang
2
Est-ce toujours une solution de travail? Lorsque j'utilise SwiftKey, j'obtiens une hauteur de 44 au lieu de 259.
KIDdAe
Fou, cela m'a aidé, mais j'avais besoin de la hauteur du clavier après qu'il était déjà affiché, alors j'observe keyboardDidShow: à la place. Pourquoi ces claviers personnalisés déclenchent-ils 3 notifications alors qu'Apple n'en déclenche qu'une? Cela semble incohérent.
Liron Yahdav
Si vous rencontrez des problèmes avec l'iPhone en mode paysage comme moi, c'est parce que la touche FIN du cadre n'a pas la bonne origine (du moins pour le clavier iOS 10 normal). KEYBOARD BEGIN RECT: (0.0, 375.0, 667.0, 162.0) ... KEYBOARD END RECT: (0.0, 213.0, 667.0, 162.0)
xaphod
18

J'ai également eu ce problème, jusqu'à ce que je tombe sur cet article StackOverflow :

Convertir UIKeyboardFrameEndUserInfoKey

Cela vous montre comment utiliser la convertRectfonction, pour convertir la taille du clavier en quelque chose utilisable, mais sur l'orientation de l'écran.

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

Auparavant, j'avais une application iPad qui a utilisé , UIKeyboardFrameEndUserInfoKeymais ne pas utiliser convertRect, et il a bien fonctionné.

Mais avec iOS 8, cela ne fonctionnait plus correctement. Du coup, il rapporterait que mon clavier, fonctionnant sur un iPad en mode paysage, faisait 1024 pixels de haut .

Alors maintenant, avec iOS 8, il est essentiel que vous utilisiez cette convertRectfonction.

Mike Gledhill
la source
Avant iOS8, le clavier droit était toujours en coordonnées d'écran orientées portrait. J'avais ajouté du code pour permuter manuellement la hauteur et la largeur en mode paysage, mais cela ne fonctionnait pas sous iOS 8. où l'orientation du clavier droit correspond à l'orientation de la vue. La solution convertRect donne un résultat correct pour iOS 7 ou iOS 8.
user1055568
7

Le similaire à la solution de dgangsta écrite 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
}
Avt
la source
problème lorsque vous affichez / masquez quickType, ainsi que le smiley
user3722523
C'était la sauce. Différence mineure dans Swift 2.3 mais c'est une suggestion de saisie semi-automatique du compilateur donc pas de problème.
Ethan Parker
5

Je fais extensionpourUIViewController

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

Vous pouvez utiliser comme ceci:

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.
}
Wanbok Choi
la source
Wanbok Choi, à quoi servent les vues inputContainerBottom?
Nathaniel Blumer
@Nathaniel UITextField ou les contraintes d'espace inférieur de UITextView à partir de bottomLayout. ;) Je l'avais édité sur mon projet. Je vais le
republier
4

Il y a des moments où les développeurs ont besoin de connaître la hauteur du clavier avant qu'il ne soit réellement affiché, ce qui leur permet de pré-configurer l'interface de manière appropriée.

Si tel est le cas, voici une spécification inclusive:

entrez la description de l'image ici

Cela inclut la barre de type rapide en haut, car elle est activée par défaut dans toutes les versions actuelles d'iOS.

Voici la configuration de la notification Swift 3 que j'ai utilisée pour tester cela, si quelqu'un en a besoin:

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)")
}
Travis M.
la source
1

Une seule chaîne pour swift:

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

UIKeyboardFrameEndUserInfoKeystocke toujours NSValue, donc pas besoin de le vérifier.

Petr Syrov
la source
0

J'ai remarqué un problème lors du basculement entre le clavier par défaut et un clavier personnalisé ( UIPickerView) - le clavier personnalisé afficherait une hauteur de 253 au lieu de 162, après le passage du clavier par défaut.

Ce qui fonctionnait dans ce cas, c'était le réglage autocorrectionType = UITextAutocorrectionTypeNo;du champ de saisie avec le clavier personnalisé.

Le problème ne s'est produit que dans iOS 8 (testé sur simulateur uniquement). Cela ne se produit pas dans iOS 9 (simulateur ou appareil).

alex-i
la source
0

Dans Swift, pas sur une seule ligne ...

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...
        }
    })
Murray Sagal
la source
0
[notificationCenter addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {

    float keyboardHeight = [[note.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;

}];
Leo Cavalcante
la source