作者:以后再试巛_113 | 来源:互联网 | 2023-01-27 16:16
iOS 11中引入的新安全区域布局指南非常适合防止内容显示在条形下方,但它不包括键盘.这意味着当显示键盘时,内容仍然隐藏在它后面,这是我想要解决的问题.
我的方法是基于听取键盘通知,然后通过调整安全区域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
通过整个安全区延伸.现在,当键盘出现时,底部被向上推,因此键盘后面没有单元格.
问题在于底栏.我底部还有一个工具栏,已经包含在安全区域中.因此,将全键盘高度设置为附加的安全区域插入会将表格视图的底部向上推动到底部条的高度.为了使这种方法运行良好,我必须将其additionalSafeAreaInsets.bottom
设置为等于键盘高度减去底栏的高度.
问题1:在底部获得当前安全区间隙的最佳方法是什么?手动获取工具栏框架并使用其高度?或者是否可以直接从安全区域布局指南中获得差距?
问题2:据推测,底栏应该可以在不改变键盘尺寸的情况下改变尺寸,因此我还应该实现一些方法来监听条形框架的变化.这是最好的viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
吗?或其他地方?
谢谢
1> Fábio Eduard..:
对我来说似乎有用的是计算view.safeAreaLayoutGuide.layoutFrame
键盘框架之间的交点,然后将其高度设置为additionalSafeAreaInsets.bottom
,而不是整个键盘框架高度.我的视图控制器中没有工具栏,但我确实有一个标签栏,并且它被正确计算.
完整代码:
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)
}
}
2> 小智..:
如果您需要支持IOS11之前的版本,可以使用Fabio中的功能并添加:
if #available(iOS 11.0, *) { }
最终解决方案
extension UIViewController {
func startAvoidingKeyboard() {
NotificationCenter.default.addObserver(self,
selector: #selector(_onKeyboardFrameWillChangeNotificationReceived(_:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
}
func stopAvoidingKeyboard() {
NotificationCenter.default.removeObserver(self,
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
}
@objc private func _onKeyboardFrameWillChangeNotificationReceived(_ notification: Notification) {
if #available(iOS 11.0, *) {
guard let userInfo = notification.userInfo,
let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] 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 animationDuration: TimeInterval = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animatiOnCurveRawNSN= notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animatiOnCurveRaw= animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
let animatiOnCurve= UIViewAnimationOptions(rawValue: animationCurveRaw)
UIView.animate(withDuration: animationDuration, delay: 0, options: animationCurve, animations: {
self.additionalSafeAreaInsets.bottom = intersection.height
self.view.layoutIfNeeded()
}, completion: nil)
}
}
}