How to detect if a key is pressed in iOS? [duplicate] - ios
I am trying to check when a text field changes, equivalent too the function used for textView - textViewDidChange so far I have done this:
func textFieldDidBeginEditing(textField: UITextField) {
if self.status.text == "" && self.username.text == "" {
self.topRightButton.enabled = false
} else {
self.topRightButton.enabled = true
}
}
Which kind of works, but the topRightButton is enabled as soon as the text field is pressed on, I want it to be enabled only when text is actually typed in?
SWIFT
Swift 4.2
textfield.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)
and
#objc func textFieldDidChange(_ textField: UITextField) {
}
SWIFT 3 & swift 4.1
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)
and
func textFieldDidChange(_ textField: UITextField) {
}
SWIFT 2.2
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged)
and
func textFieldDidChange(textField: UITextField) {
//your code
}
OBJECTIVE-C
[textField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
and textFieldDidChange method is
-(void)textFieldDidChange :(UITextField *) textField{
//your code
}
You can make this connection in interface builder.
In your storyboard, click the assistant editor at the top of the screen (two circles in the middle).
Ctrl + Click on the textfield in interface builder.
Drag from EditingChanged to inside your view controller class in the assistant view.
Name your function ("textDidChange" for example) and click connect.
Swift 5.0
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
for: .editingChanged)
and handle method:
#objc func textFieldDidChange(_ textField: UITextField) {
}
Swift 4.0
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
for: UIControlEvents.editingChanged)
and handle method:
#objc func textFieldDidChange(_ textField: UITextField) {
}
Swift 3.0
textField.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged)
and handle method:
func textFieldDidChange(textField: UITextField) {
}
The way I've handled it so far: in UITextFieldDelegate
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
// text hasn't changed yet, you have to compute the text AFTER the edit yourself
let updatedString = (textField.text as NSString?)?.stringByReplacingCharactersInRange(range, withString: string)
// do whatever you need with this updated string (your code)
// always return true so that changes propagate
return true
}
Swift4 version
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
return true
}
Swift 3
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(sender:)), for: UIControlEvents.editingChanged)
textField(_:shouldChangeCharactersIn:replacementString:) worked for me in Xcode 8, Swift 3 if you want to check every single keypress.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Whatever code you want to run here.
// Keep in mind that the textfield hasn't yet been updated,
// so use 'string' instead of 'textField.text' if you want to
// access the string the textfield will have after a user presses a key
var statusText = self.status.text
var usernameText = self.username.text
switch textField{
case self.status:
statusText = string
case self.username:
usernameText = string
default:
break
}
if statusText == "" && usernameText == "" {
self.topRightButton.enabled = false
} else {
self.topRightButton.enabled = true
}
//Return false if you don't want the textfield to be updated
return true
}
Swift 3.0.1+ (Some of the other swift 3.0 answers are not up to date)
textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
for: UIControlEvents.editingChanged)
func textFieldDidChange(_ textField: UITextField) {
}
You can use this delegate method from UITextFieldDelegate. It fires with every character change.
(Objective C) textField:shouldChangeCharactersInRange:replacementString:
(Swift) textField(_:shouldChangeCharactersInRange:replacementString:)
However THIS ONLY FIRES BEFORE a change is made (indeed, a change is only made if you do return true from here).
Swift 4
Conform to UITextFieldDelegate.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// figure out what the new string will be after the pending edit
let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
// Do whatever you want here
// Return true so that the change happens
return true
}
Maybe use RxSwift ?
need
pod 'RxSwift', '~> 3.0'
pod 'RxCocoa', '~> 3.0'
add imports obviously
import RxSwift
import RxCocoa
So u have a textfield : UITextField
let observable: Observable<String?> = textField.rx.text.asObservable()
observable.subscribe(
onNext: {(string: String?) in
print(string!)
})
U have other 3 methods..
onError
onCompleted
onDisposed
onNext
Swift 4
textField.addTarget(self, action: #selector(textIsChanging), for: UIControlEvents.editingChanged)
#objc func textIsChanging(_ textField:UITextField) {
print ("TextField is changing")
}
If you want to make a change once the user has typed in completely (It will be called once user dismiss keyboard or press enter).
textField.addTarget(self, action: #selector(textDidChange), for: UIControlEvents.editingDidEnd)
#objc func textDidChange(_ textField:UITextField) {
print ("TextField did changed")
}
You should follow this steps:
Make a Outlet reference to the textfield
AssignUITextFieldDelegate to the controller class
Configure yourTextField.delegate
Implement whatever function you need
Sample code:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var yourTextFiled : UITextField!
override func viewDidLoad() {
super.viewDidLoad()
yourTextFiled.delegate = self
}
func textFieldDidEndEditing(_ textField: UITextField) {
// your code
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// your code
}
.
.
.
}
In case it is not possible to bind the addTarget to your UITextField, I advise you to bind one of them as suggested above, and insert the code for execution at the end of the shouldChangeCharactersIn method.
nameTextField.addTarget(self, action: #selector(RegistrationViewController.textFieldDidChange(_:)), for: .editingChanged)
#objc func textFieldDidChange(_ textField: UITextField) {
if phoneNumberTextField.text!.count == 17 && nameTextField.text!.count > 0 {
continueButtonOutlet.backgroundColor = UIColor(.green)
} else {
continueButtonOutlet.backgroundColor = .systemGray
}
}
And in call in shouldChangeCharactersIn func.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else {
return true
}
let lastText = (text as NSString).replacingCharacters(in: range, with: string) as String
if phoneNumberTextField == textField {
textField.text = lastText.format("+7(NNN)-NNN-NN-NN", oldString: text)
textFieldDidChange(phoneNumberTextField)
return false
}
return true
}
There's now a UITextField delegate method available on iOS13+
optional func textFieldDidChangeSelection(_ textField: UITextField)
txf_Subject.addTarget(self, action:#selector(didChangeFirstText), for: .editingChanged)
#objc func didChangeText(textField:UITextField) {
let str = textField.text
if(str?.contains(" "))!{
let newstr = str?.replacingOccurrences(of: " ", with: "")
textField.text = newstr
}
}
#objc func didChangeFirstText(textField:UITextField) {
if(textField.text == " "){
textField.text = ""
}
}
Swift 4.2
write this in viewDidLoad
// to detect if TextField changed
TextField.addTarget(self, action: #selector(textFieldDidChange(_:)),
for: UIControl.Event.editingChanged)
write this outside viewDidLoad
#objc func textFieldDidChange(_ textField: UITextField) {
// do something
}
You could change the event by UIControl.Event.editingDidBegin or what ever you want to detect.
This is how you can add a textField text change listener using Swift 3:
Declare your class as UITextFieldDelegate
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
textField.addTarget(self, action: #selector(UITextFieldDelegate.textFieldShouldEndEditing(_:)), for: UIControlEvents.editingChanged)
}
Then just traditionally add a textFieldShouldEndEditing function:
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { // do stuff
return true
}
Just in case you are interested in a SwiftUI solution, this it's working for me:
TextField("write your answer here...",
text: Binding(
get: {
return self.query
},
set: { (newValue) in
self.fetch(query: newValue) // any action you need
return self.query = newValue
}
)
)
I have to say it's not my idea, I read it in this blog: SwiftUI binding: A very simple trick
You can manage editing either by "shouldchangecharacter" delgate or "begin and end" textfield delegate. Don't forget to set delegate
I am manage to do this using "did begin and end editing" below.
//MARK:- TextViewDelegate
extension ViewController: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
let count = self.tfEmail.text?.count ?? 0
if textField == self.tfEmail {
if count == 0{
//Empty textfield
}else{
//Non-Empty textfield
}
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == self.tfEmail{
//when user taps on textfield
}
}
}
swift 4
In viewDidLoad():
//ADD BUTTON TO DISMISS KEYBOARD
// Init a keyboard toolbar
let toolbar = UIView(frame: CGRect(x: 0, y: view.frame.size.height+44, width: view.frame.size.width, height: 44))
toolbar.backgroundColor = UIColor.clear
// Add done button
let doneButt = UIButton(frame: CGRect(x: toolbar.frame.size.width - 60, y: 0, width: 44, height: 44))
doneButt.setTitle("Done", for: .normal)
doneButt.setTitleColor(MAIN_COLOR, for: .normal)
doneButt.titleLabel?.font = UIFont(name: "Titillium-Semibold", size: 13)
doneButt.addTarget(self, action: #selector(dismissKeyboard), for: .touchUpInside)
toolbar.addSubview(doneButt)
USDTextField.inputAccessoryView = toolbar
Add this function:
#objc func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
Related
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" } }
Disable button as long as several textfields are empty
I have the following code to disable a button as long a textfield is empty: func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let text = (textField.text! as NSString).replacingCharacters(in: range, with: string) if !text.isEmpty{ addButton.isEnabled = true } else { addButton.isEnabled = false } return true } It works fine, but now that I have 3 textfields, I want the button only to be enabled, if all textfields are not empty. So far, as soon as one textfield is filled in, the button is being enabled. How can I adjust my code to do so?
Add target to all textfields for .editingChanged event, and check if any textfield is empty. If all text fields contain text enable the button else disable the button. class TestViewController: UIViewController, UITextFieldDelegate { let addButton = UIButton() let textField1 = UITextField() let textField2 = UITextField() let textField3 = UITextField() override func viewDidLoad() { super.viewDidLoad() textField1.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged) textField2.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged) textField3.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged) } #objc func textChanged(_ textField: UITextField) { addButton.isEnabled = [textField1, textField2, textField3].contains { $0.text!.isEmpty } } }
As your requirement first you have to create outlet for each textfield and you can enable the button as, #IBAction func textFieldValueChanged(_ sender: Any) { if firstTextField.text != "" && secondTextField.text != "" && thirdTextField.text != "" { addButton.isEnabled = true } else { addButton.isEnabled = false } return true And connect each textfield with the above action for valueChanged event
Well, I don't think the accepted answer is an elegant solution to this problem. I would suggest to add the following observer in your viewDidLoad: NotificationCenter.default.addObserver(self, selector: #selector(validate), name: UITextField.textDidChangeNotification, object: nil) Then define the selector: #objc func validate(){ var filteredArray = [textFieldOne,textFieldTwo,textFieldThree,textFieldFour].filter { $0?.text == "" } if !filteredArray.isEmpty { button.isHidden = true } else { button.isHidden = false } }
Prevent UITextField from taking values on changing the firstResponder
I have four UITextFields, each of which represents a single digit of an OTP. I want the control to shift to consecutive textfield as the user types in the code. My implementation is below. extension FillSignUpCodeController: UITextFieldDelegate { func textFieldDidBeginEditing(_ textField: UITextField) { textField.text = "" } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let inputString = (textField.text! as NSString).replacingCharacters(in: range, with: string) if inputString.count == 1 { switch textField { case textFieldCodeFirstDigit: textFieldCodeFirstDigit.text = inputString textFieldCodeFirstDigit.resignFirstResponder() textFieldCodeSecondDigit.becomeFirstResponder() case textFieldCodeSecondDigit: textFieldCodeSecondDigit.text = inputString textFieldCodeSecondDigit.resignFirstResponder() textFieldCodeThirdDigit.becomeFirstResponder() case textFieldCodeThirdDigit: textFieldCodeThirdDigit.text = inputString textFieldCodeThirdDigit.resignFirstResponder() textFieldCodeFourthDigit.becomeFirstResponder() case textFieldCodeFourthDigit: textFieldCodeFourthDigit.text = inputString textFieldCodeFourthDigit.resignFirstResponder() default: return false } } return true } } With this piece of code, as the user types the first digit, the first textfield takes the input value and moves the control to the next textfield. However, the second text field is taking the value of the first digit. I tried setting the text to empty after changing the firstResponder but it did not work. How can I fix this issue? Thanks.
Since textField(_:shouldChangeCharactersIn:replacementString:) executes before the text is present in the text field, you should put the code inside a method that is called when the text did already change. You should observe the changes of your text field and execute the responder-changing code there. You can find more information about that in this question. Moreover, resigning the first responder before changing it is redundant, you don't need to do that. It is also very redundant to handle every text field separately. I'd recommend including your text fields in an array and iterating through them.
shouldChangeCharactersInRange gets called before the textField is filled. You can do it by: textField.addTarget(self, action: #selector(textFieldChangedValue(textField:)), for: UIControlEvents.editingChanged) write above line for all textfields in viewDidLoad() #objc func textFieldChangedValue(textField: UITextField) { print(textField.text) } This will work
Following the answers from #the4kman and #Rahul Dasgupta, I have implemented the following: FillUpCodeViewController.swift override func viewDidLoad() { setupArrrayofTextFields(textField1: textFieldCodeFirstDigit, textField2: textFieldCodeSecondDigit, textField3: textFieldCodeThirdDigit, textField4: textFieldCodeFourthDigit) } func setupArrrayofTextFields(textField1: UITextField, textField2: UITextField, textField3: UITextField, textField4: UITextField) { arrayOftextFields = [textField1, textField2, textField3, textField4] for textField in arrayOftextFields { textField.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged) } } #objc func textFieldDidChange(textField: UITextField) { guard textField.text?.count == 0 else { let index: Int = arrayOftextFields.index(of: textField)! guard index == (arrayOftextFields.count-1) else { arrayOftextFields[index+1].becomeFirstResponder() return } textField.resignFirstResponder() return } } And, again in the viewcontroller in which I have to implement the submission of recovery code, I simply inherited the FillUpCodeViewController class. RecoveryViewController.swift override func viewDidLoad() { setupArrrayofTextFields(textField1: textFieldRecoveyCodeFirstDigit, textField2: textFieldRecoveyCodeSecondDigit, textField3: textFieldRecoveyCodeThirdDigit, textField4: textFieldRecoveyCodeFourthDigit) }
Auto switching between UITextFields with Swift
I have 4 UITextFields in one UIView like this: each UITextField limited to 4 characters. i want implement a auto switching between UITextFields with count characters of each UITextField. i use shouldChangeCharactersIn for limitation characters: func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let maxLength = 4 var newString = String() let currentString: NSString = textField.text! as NSString newString = currentString.replacingCharacters(in: range, with: string) return newString.length <= maxLength } and this is my switching implement: func textFieldDidChange(_ textField: UITextField){ let text = textField.text if text?.utf16.count == 4 { switch textField { case firstPartTextField: secondPartTextField.becomeFirstResponder() case secondPartTextField: thirdPartTextField.becomeFirstResponder() case thirdPartTextField: fourthPartTextField.becomeFirstResponder() default: break } } } my problem is switch to previous UITextField in deleting texts, i can not detect backSpace event when UITextField is empty.
Add target for textField in viewDidLoad() firstTxt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged) secTxt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged) thirdTxt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged) fourTXt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged) Than create selector method func textFieldDidChange(textField: UITextField){ let text = textField.text if text?.utf16.count == 1{ switch textField{ case firstTxt: secTxt.becomeFirstResponder() case secTxt: thirdTxt.becomeFirstResponder() case thirdTxt: fourTXt.becomeFirstResponder() case fourTXt: fourTXt.resignFirstResponder() default: break } }else{ } }
Make an outlet collection of all your textfields and configure them like so: OutletCollection: #IBOutlet var textfields: [UITextField]! Add this in viewDidLoad: for (i, tf) in textfields.enumerated() { tf.layer.cornerRadius = 5 tf.clipsToBounds = true tf.tag = i tf.delegate = self } In the target function, you'll restrict the count in this manner: func textFieldDidChange(textField: UITextField) { let text = textField.text! if text.utf16.count >= 4 { if textField.tag < 4 { codeTextfields[textField.tag + 1].becomeFirstResponder() } else { textField.resignFirstResponder() } } } This will the change in one of your delegate methods: func textFieldDidBeginEditing(_ textField: UITextField) { textField.text = "" } Refined version of the following answer: How to move cursor from one text field to another automatically in swift ios programmatically?
How do I check when a UITextField changes?
I am trying to check when a text field changes, equivalent too the function used for textView - textViewDidChange so far I have done this: func textFieldDidBeginEditing(textField: UITextField) { if self.status.text == "" && self.username.text == "" { self.topRightButton.enabled = false } else { self.topRightButton.enabled = true } } Which kind of works, but the topRightButton is enabled as soon as the text field is pressed on, I want it to be enabled only when text is actually typed in?
SWIFT Swift 4.2 textfield.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged) and #objc func textFieldDidChange(_ textField: UITextField) { } SWIFT 3 & swift 4.1 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged) and func textFieldDidChange(_ textField: UITextField) { } SWIFT 2.2 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged) and func textFieldDidChange(textField: UITextField) { //your code } OBJECTIVE-C [textField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; and textFieldDidChange method is -(void)textFieldDidChange :(UITextField *) textField{ //your code }
You can make this connection in interface builder. In your storyboard, click the assistant editor at the top of the screen (two circles in the middle). Ctrl + Click on the textfield in interface builder. Drag from EditingChanged to inside your view controller class in the assistant view. Name your function ("textDidChange" for example) and click connect.
Swift 5.0 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged) and handle method: #objc func textFieldDidChange(_ textField: UITextField) { } Swift 4.0 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: UIControlEvents.editingChanged) and handle method: #objc func textFieldDidChange(_ textField: UITextField) { } Swift 3.0 textField.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged) and handle method: func textFieldDidChange(textField: UITextField) { }
The way I've handled it so far: in UITextFieldDelegate func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { // text hasn't changed yet, you have to compute the text AFTER the edit yourself let updatedString = (textField.text as NSString?)?.stringByReplacingCharactersInRange(range, withString: string) // do whatever you need with this updated string (your code) // always return true so that changes propagate return true } Swift4 version func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) return true }
Swift 3 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(sender:)), for: UIControlEvents.editingChanged)
textField(_:shouldChangeCharactersIn:replacementString:) worked for me in Xcode 8, Swift 3 if you want to check every single keypress. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // Whatever code you want to run here. // Keep in mind that the textfield hasn't yet been updated, // so use 'string' instead of 'textField.text' if you want to // access the string the textfield will have after a user presses a key var statusText = self.status.text var usernameText = self.username.text switch textField{ case self.status: statusText = string case self.username: usernameText = string default: break } if statusText == "" && usernameText == "" { self.topRightButton.enabled = false } else { self.topRightButton.enabled = true } //Return false if you don't want the textfield to be updated return true }
Swift 3.0.1+ (Some of the other swift 3.0 answers are not up to date) textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: UIControlEvents.editingChanged) func textFieldDidChange(_ textField: UITextField) { }
You can use this delegate method from UITextFieldDelegate. It fires with every character change. (Objective C) textField:shouldChangeCharactersInRange:replacementString: (Swift) textField(_:shouldChangeCharactersInRange:replacementString:) However THIS ONLY FIRES BEFORE a change is made (indeed, a change is only made if you do return true from here).
Swift 4 Conform to UITextFieldDelegate. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // figure out what the new string will be after the pending edit let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) // Do whatever you want here // Return true so that the change happens return true }
Maybe use RxSwift ? need pod 'RxSwift', '~> 3.0' pod 'RxCocoa', '~> 3.0' add imports obviously import RxSwift import RxCocoa So u have a textfield : UITextField let observable: Observable<String?> = textField.rx.text.asObservable() observable.subscribe( onNext: {(string: String?) in print(string!) }) U have other 3 methods.. onError onCompleted onDisposed onNext
Swift 4 textField.addTarget(self, action: #selector(textIsChanging), for: UIControlEvents.editingChanged) #objc func textIsChanging(_ textField:UITextField) { print ("TextField is changing") } If you want to make a change once the user has typed in completely (It will be called once user dismiss keyboard or press enter). textField.addTarget(self, action: #selector(textDidChange), for: UIControlEvents.editingDidEnd) #objc func textDidChange(_ textField:UITextField) { print ("TextField did changed") }
You should follow this steps: Make a Outlet reference to the textfield AssignUITextFieldDelegate to the controller class Configure yourTextField.delegate Implement whatever function you need Sample code: import UIKit class ViewController: UIViewController, UITextFieldDelegate { #IBOutlet var yourTextFiled : UITextField! override func viewDidLoad() { super.viewDidLoad() yourTextFiled.delegate = self } func textFieldDidEndEditing(_ textField: UITextField) { // your code } func textFieldShouldReturn(_ textField: UITextField) -> Bool { // your code } . . . }
In case it is not possible to bind the addTarget to your UITextField, I advise you to bind one of them as suggested above, and insert the code for execution at the end of the shouldChangeCharactersIn method. nameTextField.addTarget(self, action: #selector(RegistrationViewController.textFieldDidChange(_:)), for: .editingChanged) #objc func textFieldDidChange(_ textField: UITextField) { if phoneNumberTextField.text!.count == 17 && nameTextField.text!.count > 0 { continueButtonOutlet.backgroundColor = UIColor(.green) } else { continueButtonOutlet.backgroundColor = .systemGray } } And in call in shouldChangeCharactersIn func. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { guard let text = textField.text else { return true } let lastText = (text as NSString).replacingCharacters(in: range, with: string) as String if phoneNumberTextField == textField { textField.text = lastText.format("+7(NNN)-NNN-NN-NN", oldString: text) textFieldDidChange(phoneNumberTextField) return false } return true }
There's now a UITextField delegate method available on iOS13+ optional func textFieldDidChangeSelection(_ textField: UITextField)
txf_Subject.addTarget(self, action:#selector(didChangeFirstText), for: .editingChanged) #objc func didChangeText(textField:UITextField) { let str = textField.text if(str?.contains(" "))!{ let newstr = str?.replacingOccurrences(of: " ", with: "") textField.text = newstr } } #objc func didChangeFirstText(textField:UITextField) { if(textField.text == " "){ textField.text = "" } }
Swift 4.2 write this in viewDidLoad // to detect if TextField changed TextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControl.Event.editingChanged) write this outside viewDidLoad #objc func textFieldDidChange(_ textField: UITextField) { // do something } You could change the event by UIControl.Event.editingDidBegin or what ever you want to detect.
This is how you can add a textField text change listener using Swift 3: Declare your class as UITextFieldDelegate override func viewDidLoad() { super.viewDidLoad() textField.delegate = self textField.addTarget(self, action: #selector(UITextFieldDelegate.textFieldShouldEndEditing(_:)), for: UIControlEvents.editingChanged) } Then just traditionally add a textFieldShouldEndEditing function: func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { // do stuff return true }
Just in case you are interested in a SwiftUI solution, this it's working for me: TextField("write your answer here...", text: Binding( get: { return self.query }, set: { (newValue) in self.fetch(query: newValue) // any action you need return self.query = newValue } ) ) I have to say it's not my idea, I read it in this blog: SwiftUI binding: A very simple trick
You can manage editing either by "shouldchangecharacter" delgate or "begin and end" textfield delegate. Don't forget to set delegate I am manage to do this using "did begin and end editing" below. //MARK:- TextViewDelegate extension ViewController: UITextFieldDelegate { func textFieldDidEndEditing(_ textField: UITextField) { let count = self.tfEmail.text?.count ?? 0 if textField == self.tfEmail { if count == 0{ //Empty textfield }else{ //Non-Empty textfield } } } func textFieldDidBeginEditing(_ textField: UITextField) { if textField == self.tfEmail{ //when user taps on textfield } } }
swift 4 In viewDidLoad(): //ADD BUTTON TO DISMISS KEYBOARD // Init a keyboard toolbar let toolbar = UIView(frame: CGRect(x: 0, y: view.frame.size.height+44, width: view.frame.size.width, height: 44)) toolbar.backgroundColor = UIColor.clear // Add done button let doneButt = UIButton(frame: CGRect(x: toolbar.frame.size.width - 60, y: 0, width: 44, height: 44)) doneButt.setTitle("Done", for: .normal) doneButt.setTitleColor(MAIN_COLOR, for: .normal) doneButt.titleLabel?.font = UIFont(name: "Titillium-Semibold", size: 13) doneButt.addTarget(self, action: #selector(dismissKeyboard), for: .touchUpInside) toolbar.addSubview(doneButt) USDTextField.inputAccessoryView = toolbar Add this function: #objc func dismissKeyboard() { //Causes the view (or one of its embedded text fields) to resign the first responder status. view.endEditing(true) }