iOS 如何在输入视图改变时获取键盘高度?

iOS How to get keyboard height when the inputview is changed?

我想在键盘上方放置一个文本视图。键盘有两种视图 - 一种默认视图和一种自定义视图。有一个按钮可以在这两个键盘之间切换。

我正在尝试使用以下代码将文本视图定位在键盘上方。但它的行为非常奇怪。 keyboardWillShow 通知不会一直被调用。

注意:我希望它同时支持纵向和横向。

class ViewController: UIViewController {

    let textView = UITextView()
    let button = UIButton()

    var keyboardHeight: CGFloat = 0
    var keyboardView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        textView.backgroundColor = .lightGray
        button.backgroundColor = .red
        self.view.addSubview(textView)
        self.view.addSubview(button)
    }

    @objc func buttonAction() {
        if self.textView.inputView == nil {
            self.textView.inputView = keyboardView
            self.textView.inputView?.autoresizingMask = .flexibleHeight
            self.textView.reloadInputViews()
            textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.textView.inputView!.frame.size.height - 50, width: self.view.frame.size.width - 50, height: 50)
            button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.textView.inputView!.frame.size.height - 50, width: 50, height: 50)
        } else {
            self.textView.inputView = nil
            self.textView.reloadInputViews()
            textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.keyboardHeight - 50, width: self.view.frame.size.width - 50, height: 50)
            button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.keyboardHeight - 50, width: 50, height: 50)
        }
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.keyboardHeight - 50, width: self.view.frame.size.width - 50, height: 50)
        button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.keyboardHeight - 50, width: 50, height: 50)
    }

    @objc func keyboardWillShow(notification: Notification) {
        if let userInfo = notification.userInfo {
            if let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
                self.keyboardHeight = keyboardFrame.size.height
                textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.keyboardHeight - 50, width: self.view.frame.size.width - 50, height: 50)
                button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.keyboardHeight - 50, width: 50, height: 50)
            }
        }
    }
}

如果你想在自定义键盘和系统键盘之间切换导致键盘框架发生变化时获取键盘的高度,你可以通过多种方式实现。

我个人不喜欢通知,它们总是给我一个离散值,尽管大多数实时情况下,当您需要修改 UI 时,它们已经足够好了,因为键盘框架会实时变化(比如尝试在滚动 tableView 时关闭键盘,就像什么应用程序一样,当你移动时,键盘会随着你的手指向下移动,你需要在键盘向下滚动时实时对齐视图)

无论如何,我相信下面解释的方法应该也能帮助您在切换时获得准确的键盘高度

第 1 步:

创建 UIView 的子类,稍后我们将其作为输入附件视图添加到 textView/textField

protocol KeyBoardObserverProtocol : NSObjectProtocol {
    func keyboardFrameChanged(frame : CGRect)
}

class KeyboardObserverAccessoryView: UIView {
    weak var keyboardDelegate:KeyBoardObserverProtocol? = nil
    private var kvoContext: UInt8 = 1

    override func willMove(toSuperview newSuperview: UIView?) {
        if newSuperview == nil {
            self.superview?.removeObserver(self, forKeyPath: "center")
        }
        else{
            newSuperview?.addObserver(self, forKeyPath: "center", options: [NSKeyValueObservingOptions.new, NSKeyValueObservingOptions.initial], context: &kvoContext)
        }
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if let theChange = change as [NSKeyValueChangeKey : AnyObject]?{
            if theChange[NSKeyValueChangeKey.newKey] != nil{
                if self.keyboardDelegate != nil && self.superview?.frame != nil {
                    self.keyboardDelegate?.keyboardFrameChanged(frame: (self.superview?.frame)!)
                }
            }
        }
    }
}

虽然代码看起来又大又乱,但里面的内容还是很容易理解的。它所做的就是一旦收到调用就开始使用 KVO 观察父视图框架 willMove(toSuperview newSuperview: UIView?) 因为那时你知道你的视图已移动到父视图并且你知道现在你需要监视父视图框架。

并且每次您的 KVO 触发新值时,您都会使用委托将其通知给埋葬方

如何使用?

    keyBoardObserverAccessoryView = KeyboardObserverAccessoryView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
    keyBoardObserverAccessoryView.keyboardDelegate = self
    self.textView.inputAccessoryView = keyBoardObserverAccessoryView

就是这样 :) 现在,如果您想在将来提供自定义输入附件视图,只需确保您从 KeyboardObserverAccessoryView 扩展 n 享受好处

希望对您有所帮助:)