it-swarm.com.ru

клавиатура iPhone X показывает дополнительное пространство

Я создал интерфейс чата, в котором я добавил constraint для tableView внизу экрана. Я изменяю значение ограничения, добавляя высоту клавиатуры, которая отлично работает на всех устройствах, кроме iPhone X.

Пользовательский интерфейс, когда клавиатура не видна:

 enter image description here

Что хорошо. 

Проблема в том, что когда появляется клавиатура, появляется пустое пространство между textView и клавиатурой: 

 enter image description here

Должен ли я попробовать другой подход для этого или он может быть решен с помощью ограничений?

18
Amit

Попробуйте вычесть высоту нижней вставки безопасной области при расчете значения для вашего ограничения.

Вот пример реализации, которая обрабатывает уведомление UIKeyboardWillChangeFrame.

@objc private func keyboardWillChange(_ notification: Notification) {
    guard let userInfo = (notification as Notification).userInfo, let value = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
    let newHeight: CGFloat
    if #available(iOS 11.0, *) {
        newHeight = value.cgRectValue.height - view.safeAreaInsets.bottom
    } else {
        newHeight = value.cgRectValue.height
    }
    myConstraint.value = newHeight
}
30
nathangitter

Моя проблема заключалась в том, что мое представление было в контроллере дочернего представления. Конвертация CGRect сделала свое дело.

@objc private func keyboardWillChangeFrame(notification: NSNotification) {
    guard let userInfo = notification.userInfo, let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue, let duration: TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue else {
        return
    }

    let convertedFrame = view.convert(endFrame, from: nil)
    let endFrameY = endFrame.Origin.y

    let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
    let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
    let animationCurve: UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)

    if endFrameY >= UIScreen.main.bounds.size.height {
        inputContainerViewBottomLayoutConstraint.constant = 0.0
    }  else {
        var newHeight = view.bounds.size.height - convertedFrame.Origin.y
        if #available(iOS 11.0, *) {
            newHeight = newHeight - view.safeAreaInsets.bottom
        }
        inputContainerViewBottomLayoutConstraint.constant = newHeight
    }

    UIView.animate(withDuration: duration, delay: TimeInterval(0), options: animationCurve, animations: {
        self.view.layoutIfNeeded()
    },completion: { _ in
        self.scrollView.scrollToBottom()
    })
}
0
Tyler White

Swift 4 iPhone X Мне пришлось немного подправить ответ Натана, чтобы заставить его работать. 100% это делает. 

Примечание. Убедитесь, что вы перетаскиваете элемент управления из нижнего ограничения для вашего текстового представления/представления из раскадровки в нижнюю часть вашей безопасной области в контроллере вида, а также что вы перетаскиваете элемент управления и создаете выход в своем целевом контроллере представления Project Navigator. Я назвал это bottomConstraint в моем примере. Мое поле ввода текста заключено в представление (messageInputContainerView), чтобы обеспечить дополнительное выравнивание кнопки отправки и т.д. 

 Constraint Demo

Вот код: 

@objc private func keyboardWillChange(_ notification: Notification) {
    guard let userInfo = (notification as Notification).userInfo, let value = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else {
        return
    }

    if ((userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        let isKeyboardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow
        var newHeight: CGFloat
        if isKeyboardShowing {
            if #available(iOS 11.0, *) {
                newHeight = value.cgRectValue.height - view.safeAreaInsets.bottom
                bottomConstraint.constant = newHeight

            }
        }
        else {
            newHeight = value.cgRectValue.height
            bottomConstraint?.constant = view.safeAreaInsets.bottom + messageInputContainerView.bounds.height

        }
    }
}
0
elarcoiris

Значение клавиатуры, сообщаемое UIKeyboardFrame Begin UserInfoKey, отличается в этих двух случаях в iPhone X:

  • Клавиатура не была видна, текстовое поле становится первым респондентом
  • Клавиатура уже видна, другое текстовое поле становится первым респондентом.

Чтобы получить окончательную высоту клавиатуры клавиатуры (включая вставки безопасной области), используйте UIKeyboardFrame End UserInfoKey.

В iOS 11 (особенно iPhone X) вы можете рассмотреть возможность вычитания нижней части безопасной области.

    NSValue *keyboardEndFrameValue = notification.userInfo[UIKeyboardFrameEndUserInfoKey];
    if (keyboardEndFrameValue != nil) {
        CGRect keyboardSize = [keyboardEndFrameValue CGRectValue];
        _keyboardHeight = keyboardSize.size.height;
        if (@available(iOS 11.0, *)) {
            CGFloat bottomSafeAreaInset = self.view.safeAreaInsets.bottom;
            _keyboardHeight -= bottomSafeAreaInset;
        } else {
            // Fallback on earlier versions
        }
    }
0
Raunak

Сделайте вывод о ваших ограничениях на ваш ViewController. Я буду называть это yourConstraint пока. Затем добавьте код, чтобы узнать, когда клавиатура отображается и когда она закрывается. Там вы соответственно изменяете constant ограничения. Это позволяет вам продолжать использовать ограничения.

В viewWillAppear:

NotificationCenter.default.addObserver(self, selector: #selector(YourViewController.keyboardWillShow), name:        NSNotification.Name.UIKeyboardWillShow, object: nil) // <=== Replace YourViewController with name of your view controller
NotificationCenter.default.addObserver(self, selector: #selector(YourViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil) // <=== Replace YourViewController with name of your view controller

В viewWillDisappear:

NotificationCenter.default.removeObserver(self)

В вашем UIViewController

@objc private func keyboardWillShow(notification: Notification) {
    guard let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
        yourConstraint.isActive = false // <=== 
        view.layoutIfNeeded()
        return
    }
    let duration: TimeInterval = ((notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue) ?? 0.4
    yourConstraint.constant = newValue // <===
    UIView.animate(withDuration: duration) {
        self.view.layoutIfNeeded()
    }
}

@objc private func keyboardWillHide(notification: Notification) {
    let duration: TimeInterval = ((notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue) ?? 0.4
    yourConstraint.constant = oldValue
    UIView.animate(withDuration: duration) {
        self.view.layoutIfNeeded()
    }
}

UIView.animate не обязателен (внутренняя часть блока есть), но он делает переход приятным.

0
erikmartens