nie można uzyskać poprawnej wartości wysokości klawiatury w iOS8

83

Użyłem tego kodu, aby określić, jaki jest rozmiar klawiatury:

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

}

Uruchamiam to w symulatorze.

Problem polega na tym, że iOS 8 nie da prawidłowej wartości, jeśli sugestie dotyczące klawiatury są włączone lub jeśli je popchnę, otrzymam inne (nieprawidłowe) wartości.

Jak uzyskać dokładny rozmiar klawiatury, w tym sugestie dotyczące klawiatury?

Eli Braginskiy
źródło
Może pomóc, jeśli przekonwertujesz keyboardFrameBeginRectna współrzędne lokalne.
rmaddy,
@rmaddy to nie ma znaczenia, potrzebuję tylko wysokości.
Eli Braginskiy,
Co może być błędne w zależności od orientacji. Chociaż może to już nie stanowić problemu w systemie iOS 8. Wypróbuj go i zobacz, czy to robi różnicę.
rmaddy
@rmaddy Próbowałem, ale niestety to nie pomogło
Eli Braginskiy

Odpowiedzi:

98

Posługiwać się

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
souvickcse
źródło
Świetna odpowiedź. Dzięki. Jak doszedłeś do wniosku, że powinieneś używać tego klucza? @souvickcse
Julian Osorio
6
CGRect keyboardFrame = [keyboardFrameBegin CGRectValue];
Awesomeness
12
U mnie nie działało, klawiatura wciąż była 258, za wysoko
marchinram
Dziękuję @trycatchfinally
souvickcse
1
nauczyłem się dzisiaj lekcji. Istnieje duża różnica w UIKeyboardFrameEndUserInfoKey i UIKeyboardFrameBeginUserInfoKey. Dziękuję @souvickcse
jejernig
120

Wraz z wprowadzeniem niestandardowych klawiatur w systemie iOS problem ten staje się nieco bardziej złożony.

Krótko mówiąc, UIKeyboardWillShowNotification można wywoływać wiele razy przez niestandardowe implementacje klawiatury:

  1. Gdy klawiatura systemowa Apple jest otwarta (w układzie pionowym)
    • UIKeyboardWillShowNotification jest wysyłane z klawiaturą o wysokości 224
  2. Gdy klawiatura Swype jest otwarta (w orientacji pionowej):
    • UIKeyboardWillShowNotification jest wysyłane z klawiaturą o wysokości 0
    • UIKeyboardWillShowNotification jest wysyłane z klawiaturą o wysokości 216
    • UIKeyboardWillShowNotification jest wysyłane z klawiaturą o wysokości 256
  3. Gdy klawiatura SwiftKey jest otwarta (w orientacji pionowej):
    • UIKeyboardWillShowNotification jest wysyłane z klawiaturą o wysokości 0
    • UIKeyboardWillShowNotification jest wysyłane z klawiaturą o wysokości 216
    • UIKeyboardWillShowNotification jest wysyłane z klawiaturą o wysokości 259

Aby poprawnie obsłużyć te scenariusze w jednej linii kodu, musisz:

Zarejestruj obserwatorów w powiadomieniach UIKeyboardWillShowNotification i UIKeyboardWillHideNotification :

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

Utwórz zmienną globalną, aby śledzić aktualną wysokość klawiatury:

CGFloat _currentKeyboardHeight = 0.0f;

Zaimplementuj keyboardWillShow, aby zareagować na bieżącą zmianę wysokości klawiatury:

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

UWAGA: Możesz chcieć animować przesunięcie widoków. Informacji słownik zawiera wartość wprowadzonego przez UIKeyboardAnimationDurationUserInfoKey . Ta wartość może służyć do animowania zmian z taką samą prędkością, jak wyświetlana jest klawiatura.

Zaimplementuj klawiaturęWillHide do resetowania _currentKeyboardHeight i zareaguj na odrzucenie klawiatury:

- (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
źródło
dgangsta, twoje badania są interesujące, ale problem z pytania polega tylko na uzyskaniu właściwości FrameBegin zamiast właściwości FrameEnd. Zgodnie z twoją odpowiedzią, czy rozważałeś użycie flagi UIViewAnimationOptionBeginFromCurrentState w metodzie animacji widoku zamiast delt?
MikeR
Zamiast 259 dla wysokości SwiftKey (v 1.2.3), mam 271 na iPhone6 ​​+ z iOS8.1.3.
Hemang
2
Czy to nadal działa rozwiązanie? Używając SwiftKey, otrzymuję wysokość 44 zamiast 259.
KIDdAe
Szaleństwo, to mi pomogło, ale potrzebowałem wysokości klawiatury po tym, jak była już wyświetlana, więc zamiast tego obserwuję keyboardDidShow:. Dlaczego te niestandardowe klawiatury wyzwalają 3 powiadomienia, a Apple tylko jedno? Wydaje się niespójne.
Liron Yahdav
Jeśli masz problemy z iPhonem w trybie poziomym, tak jak ja, to dlatego, że klawisz KONIEC ramki ma niewłaściwe pochodzenie (przynajmniej w przypadku normalnej klawiatury iOS 10). KEYBOARD BEGIN RECT: (0.0, 375.0, 667.0, 162.0) ... KEYBOARD END RECT: (0.0, 213.0, 667.0, 162.0)
xaphod
18

Miałem też ten problem, dopóki nie natknąłem się na ten artykuł StackOverflow :

Konwertuj UIKeyboardFrameEndUserInfoKey

To pokazuje, jak używać tej convertRectfunkcji, aby przekonwertować rozmiar klawiatury na coś użytecznego, ale z orientacją ekranu.

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

Wcześniej miałem aplikację na iPada, która była używana, UIKeyboardFrameEndUserInfoKeyale nie korzystała convertRect, i działała dobrze.

Ale z iOS 8 nie działało już poprawnie. Nagle informował, że moja klawiatura działająca na iPadzie w trybie poziomym miała 1024 piksele wysokości .

Więc teraz, w iOS 8, ważne jest, abyś używał tej convertRectfunkcji.

Mike Gledhill
źródło
Przed iOS8 prostota klawiatury była zawsze w orientacji pionowej na ekranie. Dodałem kod, aby ręcznie zamieniać wysokość i szerokość w trybie poziomym, ale to się zepsuło na iOS 8., gdzie orientacja prostokąta klawiatury odpowiada orientacji widoku. Rozwiązanie convertRect daje poprawny wynik dla iOS 7 lub iOS 8.
user1055568
7

Podobne do rozwiązania dgangsta napisanego w 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
źródło
problem podczas pokazywania / ukrywania quickType, a także buźki
user3722523
To był sos. Niewielka różnica w Swift 2.3, ale jest to sugestia autouzupełniania z kompilatora, więc nie ma problemu.
Ethan Parker
5

Robię extensiondlaUIViewController

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

Możesz użyć w ten sposób:

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
źródło
Wanbok Choi, do czego służą widoki inputContainerBottom?
Nathaniel Blumer
@Nathaniel UITextField lub ograniczenia spacji UITextView z bottomLayout. ;) Zredagowałem go w swoim projekcie.
Opublikuję
5

Są chwile, kiedy programiści muszą znać wysokość klawiatury, zanim zostanie faktycznie wyświetlona, ​​co pozwala im odpowiednio przygotować interfejs.

W takim przypadku oto szczegółowa specyfikacja:

wprowadź opis obrazu tutaj

Obejmuje to pasek szybkiego pisania u góry, ponieważ jest on domyślnie włączony we wszystkich aktualnych wersjach iOS.

Oto szybka konfiguracja powiadomień 3, której użyłem do przetestowania, jeśli ktoś tego potrzebuje:

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.
źródło
1

Tylko jeden ciąg do szybkiego:

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

UIKeyboardFrameEndUserInfoKeyzawsze przechowuje NSValue, więc nie musisz tego sprawdzać.

Petr Syrov
źródło
0

Zauważyłem problem wyświetlający się podczas przełączania między klawiaturą domyślną a niestandardową (UIPickerView ) - niestandardowa klawiatura pokazywałaby wysokość 253 zamiast 162 po przełączeniu z klawiatury domyślnej.

W tym przypadku zadziałało ustawienie autocorrectionType = UITextAutocorrectionTypeNo;pola wprowadzania za pomocą niestandardowej klawiatury.

Problem wystąpił tylko w iOS 8 (testowano tylko na symulatorze). Nie występuje w iOS 9 (symulator lub urządzenie).

alex-i
źródło
0

W Swift, nie w jednej linii ...

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

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

}];
Leo Cavalcante
źródło