Появилась клавиатура iPhone X с дополнительным пространством
Я создал пользовательский интерфейс чата, в котором я добавил constraint
для tableView
в нижней части экрана. Я изменяю значение ограничения, добавляя высоту клавиатуры, которая отлично работает на всех устройствах, кроме iPhone X.
UI, когда клавиатура не видна:
![enter image description here]()
Это нормально.
Проблема заключается в том, что клавиатура появляется, пустое пространство отображается между текстовым и клавиатурным:
![enter image description here]()
Должен ли я попробовать другой подход для этого или его можно решить с помощью ограничений?
Ответы
Ответ 1
Попробуйте вычесть высоту вставки нижней области безопасного пространства при вычислении значения для вашего ограничения.
Вот примерная реализация, которая обрабатывает уведомление 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
}
Ответ 2
Сделайте выход к своему ограничению для своего 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
не нужен (внутри блока есть), но делает переход красивым.
Ответ 3
Значение клавиатуры, указанное 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
}
}
Ответ 4
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
}
}
}
Ответ 5
Моя проблема заключалась в том, что мое представление было в контроллере дочернего представления. Конвертация 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()
})
}