如何同时获取所选UITextField的键盘大小和CGFrame?

问题描述 投票:0回答:3

我在运行时动态地填充了许多UIScrollView字段的垂直UITextField。我遇到的问题是键盘将隐藏它将出现的区域中的字段,这可能包括我正在编辑的字段。

我尝试了来自苹果文档的KeyboardManagement解决方案,并尝试了关于textFieldDidBeginEditingtextFieldDidEndEditing的通知,但两种情况下的问题是keyboardWillShow通知有时会出现,在这种情况下它不会让我知道哪个字段是编辑。

我在实现UITextFieldDelegate协议的类中有这个代码,这个类的每个对象都包含对其中一个字段的引用,并且作为它的委托工作

func textFieldDidBeginEditing(_ textField: UITextField) {
    self.activeTextfield = self.valueTextField
}

func textFieldDidEndEditing(_ textField: UITextField) {
    self.activeTextfield = nil
}

activeTextfield变量是对UIViewController变量的弱引用,其中所有这些都发生了。在该视图控制器中,我有以下代码

class MyClass: UIViewController {
    var activeTextfield: CustomTextField! // This is the variable I was talking about on the previous paragraph

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        NotificationCenter.default.removeObserver(self)
    }

    @objc func keyboardWillShow(_ notification: Notification) {
        if self.view.frame.origin.y == 0 {
            guard let userInfo = notification.userInfo else { return }
            guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }

            let keyboardFrame = keyboardSize.cgRectValue
            let textFieldFrame = activeTextfield!.frame // activeTextfield sometimes is nil because this notification happens before the previous code block

            if textFieldFrame.origin.y + textFieldFrame.size.height > keyboardFrame.origin.y {
                self.view.frame.origin.y -= keyboardFrame.height
            }
        }
    }

    @objc func keyboardWillHide(_ notification: Notification) {
        if self.view.frame.origin.y != 0 {
            guard let userInfo = notification.userInfo else { return }
            guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }

            let keyboardFrame = keyboardSize.cgRectValue

            self.view.frame.origin.y += keyboardFrame.height
        }
    }
}

有什么办法可以强制在键盘通知之前调用UITextField委托方法吗?

这是处理这种情况的正确方法吗?

如果没有,我应该如何处理?

谢谢

ios swift uitextfield uikit nsnotificationcenter
3个回答
2
投票

如您的问题所述:

两种情况下的问题都是有时会出现keyboardWillShow通知,在这种情况下,它不会让我知道哪个字段是正在编辑的字段

根据苹果文档中描述的sequence of eventstextFieldShouldBeginEditing是第一个被称为的委托方法。

所以你可以

  1. 在委托中实现textFieldShouldBeginEditing来设置你的活动文本字段,而不是textFieldDidBeginEditing(确保你从textFieldShouldBeginEditing中获取return true以允许编辑)
  2. 使用keyboardDidShowNotification而不是keyboardWillShowNotification

这将确保您在获得键盘框架/细节之前标记了UITextField


1
投票

您可以通过执行以下操作相当简单地完成此操作。首先会在视图中添加通知观察者。

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)        
    // Keyboard notification
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}

然后在你的选择器功能中你可以有这样的东西

@objc func keyboardWillShow(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
            let currentTextField = view.getSelectedTextField() {

        let keyboardHeight = keyboardSize.height
        let textFieldFrame = currentTextField.superview?.convert(currentTextField.frame, to: nil)            
        }
    }
}

而你的getSelectedTextField()扩展看起来像这样

// Inside UIView Extension 
// Get currently active textfield
func getSelectedTextField() -> UITextField? {

    let totalTextFields = getTextFieldsInView(view: self)

    for textField in totalTextFields{
        if textField.isFirstResponder{
            return textField
        }
    }
    return nil
}

    func getTextFieldsInView(view: UIView) -> [UITextField] {

        var totalTextFields = [UITextField]()

        for subview in view.subviews as [UIView] {
            if let textField = subview as? UITextField {
                totalTextFields += [textField]
            } else {
                totalTextFields += getTextFieldsInView(view: subview)
            }
        }
        return totalTextFields
    }
}

0
投票

您需要为textFields定义tag属性,并在textFieldDidBeginEditingtextFieldDidEndEditing中检查UITextField被调用的内容。

© www.soinside.com 2019 - 2024. All rights reserved.