In iOS8 kann der korrekte Wert der Tastaturhöhe nicht ermittelt werden

83

Ich habe diesen Code verwendet, um die Größe der Tastatur zu bestimmen:

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

}

Ich führe dies im Simulator aus.

Das Problem ist, dass seit iOS 8 dies nicht den richtigen Wert ergibt. Wenn die Tastaturvorschläge aktiv sind oder wenn ich sie nach unten drücke, erhalte ich unterschiedliche (nicht korrekte) Werte.

Wie kann ich die genaue Größe der Tastatur einschließlich der Tastaturvorschläge ermitteln?

Eli Braginskiy
quelle
Es kann hilfreich sein, wenn Sie keyboardFrameBeginRectin lokale Koordinaten konvertieren .
rmaddy
@rmaddy es ist eigentlich egal, ich brauche nur die höhe.
Eli Braginskiy
Was je nach Ausrichtung falsch sein könnte. Unter iOS 8 ist dies möglicherweise kein Problem mehr. Probieren Sie es aus und prüfen Sie, ob es einen Unterschied macht.
rmaddy
@rmaddy Ich habe es versucht, aber leider hat es nicht geholfen
Eli Braginskiy

Antworten:

97

Verwenden

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
souvickcse
quelle
Gute Antwort. Vielen Dank. Wie haben Sie festgestellt, dass Sie diesen Schlüssel verwenden sollten? @ Souvickcse
Julian Osorio
6
CGRect keyboardFrame = [keyboardFrameBegin CGRectValue];
Awesomeness
12
Hat bei mir nicht funktioniert, Tastatur war immer noch 258, zu hoch
Marchinram
Vielen Dank, dass Sie @trycatchfinally
souvickcse
1
habe heute eine Lektion gelernt. Es gibt einen großen Unterschied zwischen UIKeyboardFrameEndUserInfoKey und UIKeyboardFrameBeginUserInfoKey. Vielen Dank, dass Sie @souvickcse
jejernig
120

Mit der Einführung benutzerdefinierter Tastaturen in iOS wird dieses Problem etwas komplexer.

Kurz gesagt, die UIKeyboardWillShowNotification kann durch benutzerdefinierte Tastaturimplementierungen mehrmals aufgerufen werden:

  1. Wenn die Apple- Systemtastatur geöffnet wird (im Hochformat)
    • UIKeyboardWillShowNotification wird mit einer Tastaturhöhe von 224 gesendet
  2. Wenn die Swype-Tastatur geöffnet ist (im Hochformat):
    • UIKeyboardWillShowNotification wird mit einer Tastaturhöhe von 0 gesendet
    • UIKeyboardWillShowNotification wird mit einer Tastaturhöhe von 216 gesendet
    • UIKeyboardWillShowNotification wird mit einer Tastaturhöhe von 256 gesendet
  3. Wenn die SwiftKey-Tastatur geöffnet ist (im Hochformat):
    • UIKeyboardWillShowNotification wird mit einer Tastaturhöhe von 0 gesendet
    • UIKeyboardWillShowNotification wird mit einer Tastaturhöhe von 216 gesendet
    • UIKeyboardWillShowNotification wird mit einer Tastaturhöhe von 259 gesendet

Um diese Szenarien in einer Codezeile richtig zu behandeln, müssen Sie:

Registrieren Sie Beobachter für die Benachrichtigungen UIKeyboardWillShowNotification und UIKeyboardWillHideNotification :

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

Erstellen Sie eine globale Variable, um die aktuelle Tastaturhöhe zu verfolgen:

CGFloat _currentKeyboardHeight = 0.0f;

Implementieren Sie keyboardWillShow , um auf die aktuelle Änderung der Tastaturhöhe zu reagieren:

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

HINWEIS: Möglicherweise möchten Sie das Versetzen von Ansichten animieren. Das Info- Wörterbuch enthält einen von UIKeyboardAnimationDurationUserInfoKey eingegebenen Wert . Dieser Wert kann verwendet werden, um Ihre Änderungen mit der gleichen Geschwindigkeit wie die angezeigte Tastatur zu animieren.

Implementieren Sie keyboardWillHide zum Zurücksetzen von _currentKeyboardHeight und reagieren Sie darauf, dass die Tastatur geschlossen wird:

- (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
quelle
dgangsta, deine Forschung ist interessant, aber das Problem bei der Frage besteht nur darin, FrameBegin anstelle von FrameEnd-Eigenschaften zu erhalten. Haben Sie Ihrer Antwort zufolge in Betracht gezogen, das UIViewAnimationOptionBeginFromCurrentState-Flag für die Ansichtsanimationsmethode anstelle von Deltas zu verwenden?
MikeR
Statt 259 für SwiftKey (v 1.2.3) Höhe habe ich 271 in iPhone6 ​​+ mit iOS8.1.3.
Hemang
2
Ist es immer noch eine funktionierende Lösung? Wenn ich SwiftKey benutze, bekomme ich eine Höhe von 44 statt 259.
KIDdAe
Verrückt, das hat mir geholfen, aber ich brauchte die Höhe der Tastatur, nachdem sie bereits angezeigt wurde, also beobachte ich stattdessen keyboardDidShow :. Warum lösen diese benutzerdefinierten Tastaturen drei Benachrichtigungen aus, während die von Apple nur eine auslöst? Scheint inkonsistent.
Liron Yahdav
Wenn Sie Probleme mit dem iPhone im Querformat haben, wie ich es war, liegt dies daran, dass die END-Taste des Frames den falschen Ursprung hat (zumindest für eine normale iOS 10-Tastatur). KEYBOARD BEGIN RECT: (0.0, 375.0, 667.0, 162.0) ... KEYBOARD END RECT: (0.0, 213.0, 667.0, 162.0)
Xaphod
18

Ich hatte auch dieses Problem, bis ich auf diesen StackOverflow- Artikel stieß:

Konvertieren Sie UIKeyboardFrameEndUserInfoKey

Dies zeigt Ihnen, wie Sie die convertRectFunktion verwenden, um die Größe der Tastatur in etwas Verwendbares umzuwandeln, jedoch auf dem Bildschirm.

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

Zuvor hatte ich eine iPad-App, die verwendet UIKeyboardFrameEndUserInfoKey, aber nicht verwendet wurde convertRect, und sie funktionierte einwandfrei.

Aber mit iOS 8 funktionierte es nicht mehr richtig. Plötzlich wurde gemeldet, dass meine Tastatur, die auf einem iPad im Querformat ausgeführt wurde, 1024 Pixel hoch war .

Bei iOS 8 ist es daher wichtig, dass Sie diese convertRectFunktion verwenden.

Mike Gledhill
quelle
Vor iOS8 war die Tastatur direkt in hochformatigen Bildschirmkoordinaten. Ich hatte Code hinzugefügt, um Höhe und Breite im Querformat manuell zu vertauschen, aber das war unter iOS 8 nicht möglich, da die Ausrichtung der Tastatur mit der Ausrichtung der Ansicht übereinstimmt. Die convertRect-Lösung liefert das korrekte Ergebnis für iOS 7 oder iOS 8.
user1055568
7

Die ähnliche Lösung wie in Gang 2.0 von dgangsta :

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
quelle
Problem beim Ein- / Ausblenden von quickType und auch des Smileys
user3722523
Das war die Sauce. Kleiner Unterschied in Swift 2.3, aber es ist ein Autocomplete-Vorschlag des Compilers, also kein Problem.
Ethan Parker
5

Ich mache extensionfürUIViewController

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

Sie können wie folgt verwenden:

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
quelle
Wanbok Choi, wofür werden die Ansichten verwendet inputContainerBottom?
Nathaniel Blumer
@ Nathaniel UITextField oder UITextViews Einschränkungen für den unteren Speicherplatz von bottomLayout. ;) Ich hatte es in meinem Projekt bearbeitet. Ich werde es erneut veröffentlichen
Wanbok Choi
4

Es gibt Zeiten, in denen Entwickler die Tastaturhöhe kennen müssen, bevor sie tatsächlich angezeigt wird, damit sie die Benutzeroberfläche entsprechend vorab gestalten können.

Wenn dies der Fall ist, finden Sie hier eine umfassende Spezifikation:

Geben Sie hier die Bildbeschreibung ein

Dies schließt die Quick Type-Leiste oben ein, da diese in allen aktuellen Versionen von iOS standardmäßig aktiviert ist.

Hier ist das schnelle 3-Benachrichtigungs-Setup, mit dem ich dies getestet habe, falls jemand es benötigt:

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.
quelle
1

Nur eine Saite für Swift:

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

UIKeyboardFrameEndUserInfoKeyspeichert immer NSValue, so dass es nicht nötig ist, es zu überprüfen.

Petr Syrov
quelle
0

Beim Umschalten zwischen der Standardtastatur und einer benutzerdefinierten ( UIPickerView) Tastatur wurde ein Problem festgestellt. Die benutzerdefinierte Tastatur zeigte nach dem Wechsel von der Standardtastatur eine Höhe von 253 anstelle von 162 an.

In diesem Fall funktionierte die Einstellung autocorrectionType = UITextAutocorrectionTypeNo;für das Eingabefeld mit der benutzerdefinierten Tastatur.

Das Problem trat nur in iOS 8 auf (nur auf dem Simulator getestet). Es tritt in iOS 9 (Simulator oder Gerät) nicht auf.

alex-i
quelle
0

In Swift nicht in einer Zeile ...

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

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

}];
Leo Cavalcante
quelle