не могу получить правильное значение высоты клавиатуры в 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
Джулиан Осорио
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
источник
dgangsta, ваше исследование интересно, но проблема, связанная с вопросом, заключается только в получении FrameBegin вместо свойств FrameEnd. Согласно вашему ответу, рассматривали ли вы использование флага UIViewAnimationOptionBeginFromCurrentState для метода анимации просмотра вместо дельт?
MikeR
Вместо 259 для высоты SwiftKey (v 1.2.3) я получил 271 в iPhone6 ​​+ с iOS8.1.3.
Hemang
2
Это все еще рабочее решение? При использовании SwiftKey я получаю высоту 44 вместо 259.
KIDdAe
Безумно, это помогло мне, но мне нужна была высота клавиатуры после того, как она уже отображалась, поэтому я наблюдаю keyboardDidShow: вместо этого. Почему эти настраиваемые клавиатуры вызывают три уведомления, а 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
}
Avt
источник
проблема, когда вы показываете / скрываете quickType, а также смайлик
user3722523 05
Это был соус. Незначительная разница в 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. ;) Я редактировал его в своем проекте. Я сделаю репост
Ванбок Чой
5

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

Если это так, вот подробное описание:

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

Это включает в себя панель быстрого набора вверху, поскольку она по умолчанию включена во всех текущих версиях iOS.

Вот настройка уведомлений Swift 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

Только одна строка для swift:

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

UIKeyboardFrameEndUserInfoKeyвсегда хранит NSValue, поэтому не нужно его проверять.

Петр Сыров
источник
0

Я заметил проблему при переключении между клавиатурой по умолчанию и настраиваемой (UIPickerView ) клавиатурой - настраиваемая клавиатура показывала высоту 253 вместо 162 после переключения с клавиатуры по умолчанию.

В этом случае работала настройка autocorrectionType = UITextAutocorrectionTypeNo;поля ввода с помощью настраиваемой клавиатуры.

Проблема возникла только в iOS 8 (проверено только на симуляторе). Этого не происходит в iOS 9 (симулятор или устройство).

Алекс-я
источник
0

В Swift не в одну строчку ...

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;

}];
Лео Кавальканте
источник