How to call function when editing text inside of uitextfield - ios

so I have a login screen in my app. When the user clicks login, an api is called to check if the login credentials are correct (or not) and an error message is displayed when the login credentials are incorrect. Now the problem I'm having is after the login button is called and an error message is displayed, I want the error message to disappear when the user begins to change the text in the username/password field (UITextField). At first I tried using an event listener to try to set the alpha of the error message to 0.0 when the listener called a function. The code I used for that is down below.
textField.addTarget(self, action: #selector(textFieldDidChange(textfield:)), for: .editingChanged)
Then I had an objc function for that action:
#objc func textFieldDidChange(textfield: UITextField) {
errorLabel.alpha = 0.0
}
The problem I'm having with this is the error message disappears when the user only clicks on the textfield. I only want the error message to disappear if the user actually changes the text in the textfield. How should I go about this? Please let me know if you need anything else.

I wrote a quick version of the code
The solution is to create 2 variables which will do the work of storing the values of your credentials when they are wrong
import UIKit
class ViewController: UIViewController {
var usernameText:String? = nil
var passwordText:String? = nil
// we will use usernameText and PasswordText to keep track of the value of the textFields
let usernameField:UITextField = {
let textfield = UITextField()
textfield.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
return textfield
}()
let passwordField:UITextField = {
let textfield = UITextField()
textfield.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
return textfield
}()
override func viewDidLoad() {
super.viewDidLoad()
}
#objc func loginButtonTouched(){
if we touch your login button and the credentials are wrong {
// you will show the errorLabel
ErrorLabel.alpha = 1
// and give value to usernameText and passwordText
usernameText = usernameField.text
passwordText = passwordField.text
}else{
present(nextVC) // for example
}
}
// the username and the password textField have the same action if the text change
#objc func textFieldDidChange(_ textfield: UITextField) {
// now we will use the values we gave to usernameText and passwordText to check if one of them has changed their value
if usernameText != usernameField.text || passwordText != passwordField.text {
// if one of them changed their value we make disappear the errorLabel
ErrorLabel.alpha = 0.0
}
}
}

Related

UITextField: resign keyboard after clearButton is pressed

I have a UITextfield in a storyboard.
ClearButton is set to 'is always visible'
searchTextField.addTarget(self, action: #selector(searchTextFieldDidChange(textField:)), for: .editingChanged)
When the text field changes, this method is called
#objc func searchTextFieldDidChange(textField: UITextField){
if textField.text == "" {
textField.resignFirstResponder()
}
fireSearch()
}
When I clear the text field using backspace, textField.resignFirstResponder() is called, the keyboard vanishes as I want it.
When I clear the text field using the clear button, textField.resignFirstResponder() is called, the keyboard vanishes and appears again immediately.
What can I do that the keyboard keeps being closed when I tap the clear button?
Give this a try...
// conform to UITextFieldDelegate
class ViewController: UIViewController, UITextFieldDelegate {
// assuming this is created in Storyboard
#IBOutlet var searchTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
searchTextField.addTarget(self, action: #selector(searchTextFieldDidChange(textField:)), for: .editingChanged)
// set the delegate
searchTextField.delegate = self
}
#objc func searchTextFieldDidChange(textField: UITextField){
if textField.text == "" {
textField.resignFirstResponder()
}
fireSearch()
}
func textFieldShouldClear(_ textField: UITextField) -> Bool {
// clear the text
// Note: this does NOT fire searchTextFieldDidChange()
textField.text = ""
// resign
textField.resignFirstResponder()
// if you want to fire the search after text has been cleared
//fireSearch()
// return false to stop the default action of the clear button
return false
}
func fireSearch() {
print(#function)
}
}

Replace empty UITextfield with value

I am building a digit only textfield.
I would like that when the text in textfield is "" replace it with "0".
I only manage to get the current text in read only.
Thanks in advance
Add the editingChanged delegate method to textField as follows:
In the viewDidLoad() method add the following code:
textField.addTarget(self, action: #selector(textFieldChanged(_:)), for: .editingChanged);
And then, implement the method as follows:
#objc func textFieldChanged(_ textField: UITextField) {
if let text = textField.text, text.isEmpty {
textField.text = "0"
}
}
The above method will be called every time the textField content changes.
You can also set the initial text of the textField to "0". Simply use textField.text = "0" in the viewDidLoad() method.
If you want the text field to update when you have finished editing you can set up the action like this
and then
#IBAction func editingDidEnd(_ txtTest: UITextField) {
if txtTest.text == ""
{
txtTest.text = "0"
}
textField.addTarget(self, action: #selector(handleTextField(_:)), for: .editingChanged)
#objc private func handleTextField(_ textField: UITextField) {
if textField.text == "" {
textFiled.text = "0"
}
}

Xcode: Dismiss keyboard after tapping autofill

In Swift, I want to detect when the user has finished adding their username/password using autofill (from https://developer.apple.com/documentation/security/password_autofill) and not reopen the keyboard, since they're presumably done using the keyboard.
Here's how I've setup their username/password inputs:
override func viewDidLoad() {
super.viewDidLoad()
name.textContentType = .username
password.textContentType = .password
loginButton.addTarget(self, action: #selector(self.loginPressed), for: .touchUpInside)
}
#objc func loginPressed() {
// Making server calls here
}
Right now, after I hit an autofill username, my iOS runs the FaceID check, then reopens the keyboard. The user has to manually close the keyboard after.
When a user uses autofill, depending on which type of view you use to get text input, a certain delegate method is called, as well as a textDidChangeNotification (docs). For UITextField the method is (textField(_:shouldChangeCharactersIn:replacementString:)). The string passed in is whatever new string is added, and "normally contains only the single new character that was typed" but if the user uses autofill, or pastes in a password, the number of characters in the string will be longer. You could try checking for that and calling endEditing if more than one new character is added.
override func viewDidLoad() {
super.viewDidLoad()
name.textContentType = .username
password.textContentType = .password
//set delegate
name.delegate = self
password.delegate = self
loginButton.addTarget(self, action:
#selector(self.loginPressed),
for: .touchUpInside)
}
#objc func loginPressed() {
// Making server calls here
}
extension UIViewController: UITextFieldDelegate
{
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if textField == name
{
DispatchQueue.main.async {
self.view.endEditing(true)
}
}
return true
}
}

UITextField returns value held before edit

I have textField. For that textField, I added the following target and function.
textField.addTarget(target: self, action: #selector(self.textDidChange), for: UIControlEvents.editingChanged)
func textDidChanged() {
label.text = textField.text
}
Strange thing I encounter is whenever the textDidChanged is called textField returns the previous state of value.
Eg: What I entered in TextFiled --> What I got in Label
"a" ----> ""
"aa" ----> "a"
"a" ----> "aa"
textField.text return value before my edit.
Is it something wrong in my doing. Guide me. Thanks.
override func viewDidLoad() {
super.viewDidLoad()
self.textfield.addTarget(self, action: #selector(textDidChanged), for: UIControl.Event.editingChanged)
}
#objc func textDidChanged() {
label.text = textfield.text
}
This works in Xcode10.

textfield click vs drag

I have a text field which can be clicked to edit, and dragged along the y-axis using a UIPanGesture.
When the user clicks the text field, I want to set the textAlignement to.left & when the user drags the text field around, I want to keep the text center aligned.
I initialise in the viewDidLoad method:
let dragText = UIPanGestureRecognizer(target: self, action: #selector(userDragged))
textOverlay.addGestureRecognizer(dragText)
textOverlay.addTarget(self, action: #selector(textClicked), for: UIControlEvents.touchDown)
Callback methods:
func textClicked() {
//let actLocation = textOverlay.frame.origin.y
textOverlay.frame.origin.y = self.finalKBH
self.textOverlay.textAlignment = .left
print("Text clicked")
}
func userDragged(gesture: UIPanGestureRecognizer) {
let loc = gesture.location(in: self.view)
self.textOverlay.frame.origin.y = loc.y
self.textOverlay.textAlignment = .center
print("Text dragged")
}
The problem I'm having, is differentiating between an actual 'click-to-edit' and drag gesture.
While dragging the text field, the textClicked function is also called and the text is aligned to the left.
Is there a way I can differentiate between these two actions?
I've attempted to change the textClicked targer to UIControlEvents.touchUpInside but then my function isn't being registered in the console.
Many thanks in advance
For detecting when the textfield enters editing mode, implement the textFieldDidBeginEditing(_:) method of UITextFieldDelegate
override func viewDidLoad()
{
super.viewDidLoad()
// ...
textField.delegate = self
}
func textFieldDidBeginEditing(_ textField: UITextField)
{
print("Text clicked")
}
Maybe, long press if you have to use an overlay for some reason?
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "longPressed:")
textOverlay.addGestureRecognizer(longPressRecognizer)

Resources