简体   繁体   English

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

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

I am trying to place a textview just above the keyboard. 我试图在键盘上方放置一个textview。 The keyboard has two views - one default view and one custom view. 键盘有两个视图-一个默认视图和一个自定义视图。 A button is there to toggle between these two keyboards. 有一个按钮可在这两个键盘之间切换。

I am trying to use the following code to position the textview just above the keyboard. 我试图使用以下代码将textview定位在键盘上方。 But it is behaving very weirdly. 但是它表现得很奇怪。 The keyboardWillShow notification is not getting called all the times. keyboardWillShow通知并非一直被调用。

Note: I wanted it to support for both portrait and landscape. 注意:我希望它同时支持纵向和横向。

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)
            }
        }
    }
}

If you wanna get the height of Keyboard when keyboard frame changes because of you toggling between custom keyboard and system keyboard, you can achieve it many ways. 如果您想在自定义键盘和系统键盘之间切换时更改键盘框架,从而获得键盘的高度,则可以采用多种方法来实现。

I personally dont prefer notifications they always end up giving me a discrete values, though most of the realtime cases they are good enough when you need to modify the UI as keyboard frame changes in real time (Like try dismissing keyboard on scrolling tableView like whats app where keyboard would go down with your finger as u move and u need to align views in realtime when keyboards scrolls down) 我个人不希望通知总是总是给我一个离散的值,尽管在大多数实时情况下,当您需要实时更改键盘框架时需要修改UI时,它们已经足够好了(例如,尝试在滚动tableView上关闭键盘)当您移动键盘时,键盘会随着您的手指向下移动,并且当键盘向下滚动时,您需要实时对齐视图)

Anyway I believe the approach explained below should also help u to get accurate keyboard height when toggled 无论如何,我相信以下说明的方法也应该有助于您在切换时获得准确的键盘高度

Step 1: 第1步:

Create a subclass of UIView which we will be adding as input accessory view to textView/textField later 创建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)!)
                }
            }
        }
    }
}

Though code looks big and messy whats inside is pretty easy to understand. 虽然代码看起来很大而且很乱,但是里面的内容却很容易理解。 All it does is it start obseving the parent view frame using KVO once it receives the call willMove(toSuperview newSuperview: UIView?) because thats when you know ur view is moved to parent and u know that now u need to monitor the parent's frame. 它所做的只是在收到调用willMove(toSuperview newSuperview: UIView?)开始使用KVO观察父视图框架,因为那是当您知道您的视图已移至父视图并且您知道现在需要监视父框架时。

And every time your KVO triggers the new value u inform it to the interred party using the delegate 每次您的KVO触发新值时,您都会使用委托将其告知被邀请方

How to use it? 如何使用它?

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

Thats it :) Now if you wanna provide your custom input accessory view in future just make sure u extend from KeyboardObserverAccessoryView n enjoy the benefits 就是这样:)现在,如果您将来想提供自定义的输入附件视图,只需确保您从KeyboardObserverAccessoryView扩展即可,享受到的好处

Hope it helps :) 希望能帮助到你 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM