не вдається отримати правильне значення висоти клавіатури в iOS8


83

Я використовував цей код, щоб визначити розмір клавіатури:

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

}

Я запускаю це в тренажері.

Проблема в тому, що iOS 8 це не дасть правильного значення, якщо пропозиції клавіатури вгору або якщо я натискаю їх вниз, я отримую різні (не правильні) значення.

Як я можу отримати точний розмір клавіатури, включаючи пропозиції щодо клавіатури?


Це може допомогти, якщо перетворити keyboardFrameBeginRectна місцеві координати.
rmaddy

@rmaddy це насправді не має значення, мені потрібна лише висота.
Елі Брагінський

Що може бути помилковим залежно від орієнтації. Хоча це може не бути проблемою під iOS 8. Спробуйте, хоч і переконайтеся, що це має значення.
rmaddy

@rmaddy Я спробував, але, на жаль, це не допомогло
Елі Брагінський

Відповіді:


98

Використовуйте

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];

Чудова відповідь. Дякую. Як ви виявили, що вам слід використовувати цей ключ? @souvickcse
Julian Osorio

6
CGRect keyboardFrame = [keyboardFrameBegin CGRectValue];
Awesomeness

12
У мене не вийшло, клавіатура все ще була 258, занадто висока
марчінрам

Дякую @trycatchfinally
souvickcse

1
сьогодні вивчив урок. Існує велика різниця в UIKeyboardFrameEndUserInfoKey та UIKeyboardFrameBeginUserInfoKey. Дякую @souvickcse
jejernig

120

З впровадженням спеціальних клавіатур в iOS ця проблема стає трохи складнішою.

Коротше кажучи, UIKeyboardWillShowNotification може викликатися кілька разів за допомогою реалізацій спеціальних клавіатур:

  1. Коли відкрита системна клавіатура Apple (у вертикальному режимі)
    • UIKeyboardWillShowNotification надсилається з висотою клавіатури 224
  2. Коли відкрита клавіатура Swype (у книжковому режимі):
    • UIKeyboardWillShowNotification надсилається з висотою клавіатури 0
    • UIKeyboardWillShowNotification надсилається з висотою клавіатури 216
    • UIKeyboardWillShowNotification надсилається з висотою клавіатури 256
  3. Коли клавіатуру SwiftKey відкрито (у портретному режимі):
    • UIKeyboardWillShowNotification надсилається з висотою клавіатури 0
    • UIKeyboardWillShowNotification надсилається з висотою клавіатури 216
    • UIKeyboardWillShowNotification надсилається з висотою клавіатури 259

Щоб правильно обробляти ці сценарії в одному кодовому рядку, вам потрібно:

Зареєструйте спостерігачів за повідомленнями UIKeyboardWillShowNotification та UIKeyboardWillHideNotification :

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

Створіть глобальну змінну для відстеження поточної висоти клавіатури:

CGFloat _currentKeyboardHeight = 0.0f;

Впровадити keyboardWillShow реагувати на поточну зміну висоти клавіатури:

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

ПРИМІТКА. Можливо, ви захочете анімувати зміщення подань. Інформація про словнику містить значення заклиненого по UIKeyboardAnimationDurationUserInfoKey . Це значення можна використовувати для анімування змін із такою ж швидкістю, що і відображається клавіатура.

Реалізуйте keyboardWillHide для скидання _currentKeyboardHeight і реагуйте на відхилену клавіатуру:

- (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, ваше дослідження цікаве, але проблема у питанні полягає лише в отриманні FrameBegin замість властивостей FrameEnd. Відповідно до вашої відповіді, чи замислювались ви про використання прапора UIViewAnimationOptionBeginFromCurrentState до методу перегляду анімації замість дельт?
MikeR

Натомість 259 для висоти SwiftKey (v 1.2.3), я отримав 271 в iPhone6 ​​+ з iOS8.1.3.
Hemang

2
Це все ще робоче рішення? При використанні SwiftKey я отримую висоту 44 замість 259.
KIDdAe

Божевільний, це мені допомогло, але мені потрібна була висота клавіатури після того, як вона вже відображалась, тому я спостерігаю за keyboardDidShow: замість цього. Чому ці спеціальні клавіатури запускають 3 сповіщення, тоді як Apple просто запускає одне? Виглядає непослідовно.
Лірон Ягдав,

Якщо у вас проблеми з iPhone у альбомному режимі, як у мене, це тому, що клавіша END в кадрі має неправильне походження (принаймні для звичайної клавіатури 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

У мене також була ця проблема, поки я не натрапив на цю статтю StackOverflow :

Перетворити UIKeyboardFrameEndUserInfoKey

Це покаже вам, як використовувати convertRectфункцію, щоб перетворити розмір клавіатури на щось корисне, але в орієнтації екрана.

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

Раніше я мав додаток для iPad, який використовував, UIKeyboardFrameEndUserInfoKeyале не використовував convertRect, і він працював нормально.

Але з iOS 8 він більше не працював належним чином. Раптом він повідомить, що моя клавіатура, що працює на iPad у альбомному режимі, мала висоту 1024 пікселі .

Отже, зараз з iOS 8 дуже важливо використовувати цю convertRectфункцію.


До iOS8 клавіатура прямокутника завжди була в портретно орієнтованих координатах екрана. Я додав код, щоб вручну поміняти місцями висоту та ширину в альбомному режимі, але це не вдалося на iOS 8. Де орієнтація прямої клавіатури відповідає орієнтації вигляду. Рішення convertRect дає правильний результат для iOS 7 або iOS 8.
user1055568 02

7

Подібне рішення dgangsta, написане в 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
}

проблема, коли ви показуєте / приховуєте quickType, а також смайлик
user3722523

Це був соус. Незначна різниця в Swift 2.3, але це пропозиція автозаповнення від компілятора, тому жодної проблеми.
Ітан Паркер,

5

Я роблю extensionдля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
        )
    }
}

Ви можете використовувати так:

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

Ванбок Чой, для чого використовуються погляди inputContainerBottom?
Натаніель Блюмер

@Nathaniel UITextField або обмеження нижнього простору UITextView від bottomLayout. ;) Я відредагував його у своєму проекті. Я
перепублікую

4

Бувають випадки, коли розробники повинні знати висоту клавіатури, перш ніж вона насправді відображається, що дозволяє їм попередньо розкласти інтерфейс належним чином.

Якщо це так, ось інклюзивна специфікація:

введіть тут опис зображення

Сюди входить панель швидкого введення вгорі, оскільки вона ввімкнена за замовчуванням у всіх поточних версіях iOS.

Ось швидке налаштування сповіщень 3, яке я використовував, щоб перевірити це, якщо комусь це потрібно:

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

Тільки один рядок для швидкого:

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

UIKeyboardFrameEndUserInfoKeyзавжди зберігає NSValue, тому не потрібно це перевіряти.


0

Я помітив проблему, що відображається під час перемикання між типовою клавіатурою та нестандартною (UIPickerView ) клавіатурою - спеціальна клавіатура відображатиме висоту 253 замість 162 після перемикання з клавіатури за замовчуванням.

Що спрацювало у цій справі, це настройка autocorrectionType = UITextAutocorrectionTypeNo; поля введення за допомогою спеціальної клавіатури.

Проблема сталася лише в iOS 8 (протестовано лише на симуляторі). Це не відбувається в iOS 9 (симулятор або пристрій).


0

У Свіфті, не в одному рядку ...

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;

}];
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.