扩展iOS 11安全区域以包括键盘

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,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,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,right: 0)

        UIView.animate(withDuration: 0.3) {
            self.view.layoutIfNeeded();
        }
    }
}

这很好用,因为MyController是一个带有UITableView的UIViewController,它可以扩展到整个安全区域.现在当键盘出现时,底部被向上推,因此键盘后面没有单元格.

问题在于底栏.我底部还有一个工具栏,已经包含在安全区域中.因此,将全键盘高度设置为额外的安全区域插入会将表格视图的底部向上推动过多地与底栏的高度相对应.为了使这个方法运行良好,我必须将additionalSafeAreaInsets.bottom设置为等于键盘高度减去底栏的高度.

问题1:在底部获得当前安全区间隙的最佳方法是什么?手动获取工具栏框架并使用其高度?或者是否可以直接从安全区域布局指南中获得差距?

问题2:据推测,如果没有键盘改变大小,底栏应该可以改变大小,所以我也应该实现一些方法来监听栏中框架的变化.这是最好的在viewWillTransition中完成(大小:CGSize,与协调员:UIViewControllerTransitionCoordinator)?或其他地方?

谢谢

解决方法

对我来说似乎有用的是计算view.safeAreaLayoutGuide.layoutFrame和键盘框架之间的交集,然后将其高度设置为additionalSafeAreaInsets.bottom,而不是整个键盘框架高度.我的视图控制器中没有工具栏,但我有一个标签栏,并且它被正确计算.

完整代码

extension UIViewController {

    func startAvoidingKeyboard() {
        NotificationCenter.default.addobserver(self,selector: #selector(_onKeyboardFrameWillChangeNotificationReceived(_:)),object: nil)
    }

    func stopAvoidingKeyboard() {
        NotificationCenter.default.removeObserver(self,object: nil)
    }

    @objc private func _onKeyboardFrameWillChangeNotificationReceived(_ notification: Notification) {
        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)
    }
}

相关文章

当我们远离最新的 iOS 16 更新版本时,我们听到了困扰 Apple...
欧版/美版 特别说一下,美版选错了 可能会永久丧失4G,不过只...
一般在接外包的时候, 通常第三方需要安装你的app进行测...
前言为了让更多的人永远记住12月13日,各大厂都在这一天将应...