【问题标题】:iOS How to get keyboard height when the inputview is changed?iOS 如何在输入视图更改时获取键盘高度?
【发布时间】:2018-03-21 20:27:41
【问题描述】:

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

我正在尝试使用以下代码将 textview 定位在键盘上方。但它的行为非常奇怪。不会一直调用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)
            }
        }
    }
}

【问题讨论】:

    标签: ios swift keyboard custom-keyboard


    【解决方案1】:

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

    我个人不喜欢通知,它们总是最终给我一个离散值,尽管在大多数实时情况下,当您需要修改 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)!)
                    }
                }
            }
        }
    }
    

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

    每次您的 KVO 触发新值时,您都会使用委托将其通知给相关方

    如何使用?

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

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

    希望对你有帮助:)

    【讨论】:

    • 哇,Sandeep 的解决方案很棒。有效。非常感谢。我有一个疑问。你为什么使用 kvoContext?当我完全使用这段代码时,它显示了一些线程错误。所以我删除了“if context == &kvoContext {”行并将参数更改为 nil,它工作正常。
    • @grovile :抱歉,这是从我的工作代码库中复制粘贴的代码,我添加了多个 KVO,我的输入附件视图不仅仅是观察父框架,所以我需要一种方法为了区分上下文,我添加了 if。不知道它对你来说是如何崩溃的,但如果你只有一个 KVO,那么正如你所说,你可以删除它:) 感谢您指出
    猜你喜欢
    • 2014-11-24
    • 2016-12-26
    • 1970-01-01
    • 2015-04-18
    • 1970-01-01
    • 1970-01-01
    • 2021-09-05
    • 2014-05-26
    • 2013-10-10
    相关资源
    最近更新 更多