There is a view with two UITextFields, and the view moves according to the height of the keyboard. However, moving the View is not ideal if at least one textfield has its isSecureTextEntry property set to true. It is noticeable when moving between textfields. View moves down once and returns instantly. This is because the height of the keyboard changes momentarily. I think it's a matter of showing / hiding QuickTypeBar. So how to eliminate that effect and control the view movement?
Below is all the code. It may not look right in the simulator. Because the QuickType bar is not displayed. This is happening on the iPhone X iOS13.3.1.
Thanks.
import UIKit
class ViewController: UIViewController {
public var boardView: UIView!
public var usernameTextField: UITextField!
public var passwordTextField: UITextField!
public var boardViewBottomAnchorConstraint: NSLayoutConstraint!
public var boardViewBottomAnchorConstraintConstant: CGFloat = -220
public var offset: CGFloat = 16.0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .darkGray
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
var constraints = [NSLayoutConstraint]()
let boardView = UIView()
boardView.backgroundColor = .brown
boardView.layer.cornerRadius = 16.0
boardView.translatesAutoresizingMaskIntoConstraints = false
boardViewBottomAnchorConstraint = boardView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: boardViewBottomAnchorConstraintConstant)
constraints.append(boardView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 16))
constraints.append(boardViewBottomAnchorConstraint)
constraints.append(boardView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -16))
view.addSubview(boardView)
self.boardView = boardView
let usernameTextField = UITextField()
usernameTextField.backgroundColor = .white
usernameTextField.delegate = self
usernameTextField.returnKeyType = .next
usernameTextField.textContentType = .username
usernameTextField.placeholder = "USERNAME TEXTFIELD"
usernameTextField.translatesAutoresizingMaskIntoConstraints = false
constraints.append(usernameTextField.heightAnchor.constraint(equalToConstant: 56))
constraints.append(usernameTextField.topAnchor.constraint(equalTo: boardView.topAnchor, constant: 100))
constraints.append(usernameTextField.leftAnchor.constraint(equalTo: boardView.leftAnchor, constant: 24))
constraints.append(usernameTextField.rightAnchor.constraint(equalTo: boardView.rightAnchor, constant: -24))
boardView.addSubview(usernameTextField)
self.usernameTextField = usernameTextField
let passwordTextField = UITextField()
passwordTextField.backgroundColor = .white
passwordTextField.delegate = self
passwordTextField.returnKeyType = .go
passwordTextField.textContentType = .password
passwordTextField.placeholder = "PASSWORD TEXTFIELD"
passwordTextField.translatesAutoresizingMaskIntoConstraints = false
constraints.append(passwordTextField.heightAnchor.constraint(equalToConstant: 56))
constraints.append(passwordTextField.topAnchor.constraint(equalTo: usernameTextField.bottomAnchor, constant: 50))
constraints.append(passwordTextField.leftAnchor.constraint(equalTo: boardView.leftAnchor, constant: 24))
constraints.append(passwordTextField.bottomAnchor.constraint(equalTo: boardView.bottomAnchor, constant: -100))
constraints.append(passwordTextField.rightAnchor.constraint(equalTo: boardView.rightAnchor, constant: -24))
boardView.addSubview(passwordTextField)
self.passwordTextField = passwordTextField
NSLayoutConstraint.activate(constraints)
let tap = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:)))
view.addGestureRecognizer(tap)
// false is the ideal move. If true, the view moves violently.
passwordTextField.isSecureTextEntry = true
}
}
extension ViewController {
@objc
public func keyboardWillShow(_ notification: Notification) { print("WILL SHOW")
updateConstraints(notification)
}
@objc
public func keyboardWillHide(_ notification: Notification) { print("WILL HIDE")
boardViewBottomAnchorConstraint.constant = boardViewBottomAnchorConstraintConstant
view.layoutIfNeeded()
}
@objc
public func keyboardWillChangeFrame(_ notification: Notification) { print("WILL CHANGE FRAME")
updateConstraints(notification)
}
private func updateConstraints(_ notification: Notification) {
guard
let toFrame = notification.userInfo?[UIApplication.keyboardFrameEndUserInfoKey] as? CGRect,
let fromFrame = notification.userInfo?[UIApplication.keyboardFrameBeginUserInfoKey] as? CGRect else { return }
print(fromFrame); print(toFrame);
let constant = -toFrame.size.height - offset
boardViewBottomAnchorConstraint.constant = constant
view.layoutIfNeeded()
}
}
extension ViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == usernameTextField {
passwordTextField.becomeFirstResponder()
} else {
passwordTextField.resignFirstResponder()
}
return true
}
}