iOS 11 中引入的新安全区域布局指南非常适合防止内容显示在栏下方,但它不包括键盘.这意味着当显示键盘时,内容仍然隐藏在它后面,这就是我要解决的问题.
The new Safe Area layout guide introduced in iOS 11 works great to prevent content from displaying below bars, but it excludes the keyboard. That means that when a keyboard is displayed, content is still hidden behind it and this is the problem I am trying to solve.
我的做法是基于监听键盘通知,然后通过additionalSafeAreaInsets
调整安全区域.
My approach is based on listening to keyboard notifications and then adjusting the safe area through additionalSafeAreaInsets
.
这是我的代码:
override func viewDidLoad() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
notificationCenter.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
notificationCenter.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
//MARK: - Keyboard
extension MyViewController {
@objc func keyboardWillShow(notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0)
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded();
}
}
@objc func keyboardWillHide(notification: NSNotification) {
additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded();
}
}
@objc func keyboardWillChange(notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0)
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded();
}
}
}
这很好用,因为 MyController
是一个 UIViewController
和一个延伸到整个安全区域的 UITableView
.现在当键盘出现时,底部被向上推,这样键盘后面就没有单元格了.
This works well as the MyController
is a UIViewController
with a UITableView
that extends through the whole safe area. Now when the keyboard appears, the bottom is pushed up so that no cells are behind the keyboard.
问题在于底栏.我在底部还有一个工具栏,它已经包含在安全区域中.因此,将全键盘高度设置为额外的安全区域插入会将表格视图的底部向上推太多,正好是底部栏的高度.为了使这种方法正常工作,我必须将 additionalSafeAreaInsets.bottom
设置为等于键盘高度减去底栏的高度.
The problem is with bottom bars. I also have a toolbar at the bottom which is already included in the safe area. Therefore, setting full keyboard height as additional safe area inset pushes the bottom of the table view up too much by exactly the height of the bottom bar. For this method to work well, I must set the additionalSafeAreaInsets.bottom
to be equal to the keyboard height minus the height of the bottom bar.
问题1:获得底部当前安全区域间隙的最佳方法是什么?手动获取工具栏的框架并使用它的高度?或者是否可以直接从安全区布局指南中获取间隙?
Question 1: What is the best way to get the current safe area gap on the bottom? Manually get frame of toolbar and use its height? Or is it possible to get the gap directly from the safe area layout guide?
问题2:大概底部栏应该可以在不改变键盘大小的情况下改变大小,所以我还应该实现一些方法来监听栏的框架变化.这最好在 viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
中完成吗?还是其他地方?
Question 2: Presumably it should be possible for the bottom bar to change size without the keyboard changing size so I should also implement some method listening to change in frame of the bar. Is this best done in viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
? Or elsewhere?
谢谢
似乎对我有用的是计算 view.safeAreaLayoutGuide.layoutFrame
和键盘框架之间的交集,然后设置additionalSafeAreaInsets.bottom
的高度,而不是整个键盘框架的高度.我的视图控制器中没有工具栏,但我确实有一个标签栏,并且它被正确解释了.
What seems to be working for me is to calculate the intersection between view.safeAreaLayoutGuide.layoutFrame
and the keyboard frame, and then setting the height of that as the additionalSafeAreaInsets.bottom
, instead of the whole keyboard frame height. I don't have a toolbar in my view controller, but I do have a tab bar and it is accounted for correctly.
完整代码:
import UIKit
public extension UIViewController
{
func startAvoidingKeyboard()
{
NotificationCenter.default
.addObserver(self,
selector: #selector(onKeyboardFrameWillChangeNotificationReceived(_:)),
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil)
}
func stopAvoidingKeyboard()
{
NotificationCenter.default
.removeObserver(self,
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil)
}
@objc
private func onKeyboardFrameWillChangeNotificationReceived(_ notification: Notification)
{
guard
let userInfo = notification.userInfo,
let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
else {
return
}
let keyboardFrameInView = view.convert(keyboardFrame, from: nil)
let safeAreaFrame = view.safeAreaLayoutGuide.layoutFrame.insetBy(dx: 0, dy: -additionalSafeAreaInsets.bottom)
let intersection = safeAreaFrame.intersection(keyboardFrameInView)
let keyboardAnimationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey]
let animationDuration: TimeInterval = (keyboardAnimationDuration as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
let animationCurve = UIView.AnimationOptions(rawValue: animationCurveRaw)
UIView.animate(withDuration: animationDuration,
delay: 0,
options: animationCurve,
animations: {
self.additionalSafeAreaInsets.bottom = intersection.height
self.view.layoutIfNeeded()
}, completion: nil)
}
}
这篇关于扩展 iOS 11 安全区域以包括键盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!