I'm populating a vertical UIScrollView
with many UITextField
fields dynamically on runtime. The problem I have is that the keyboard will hide the fields that are in the area where it will appear, this may include the field I'm editing.
I tried KeyboardManagement solution from the apple documentation and also tried with notifications on the textFieldDidBeginEditing
and textFieldDidEndEditing
but the problem in both cases is that the keyboardWillShow
notification comes first sometimes, and in that case it doesn't let me know which field is the one being edited.
I have this code in a class that implements the UITextFieldDelegate
protocol, each object of this class holds a reference to one of those fields and works as it's delegate
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeTextfield = self.valueTextField
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.activeTextfield = nil
}
The activeTextfield
variable is a weak reference to the variable in the UIViewController
where all of this happens. In that view controller I have the following code
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
}
}
}
Is there any way I can force the UITextField
delegate methods to be called before the keyboard notification?
Is this the correct way to handle this kind of situation?
If not, how should I handle it?
Thanks