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?


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];

Ś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, 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.


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
}

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

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ć.


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


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

0
[notificationCenter addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {

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

}];
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.