Related
I'm trying to give a background color to a UITextField using SwiftUI since I'm trying to use some unique colours in my app to support both LightMode and DarkMode.
My colors are always defined as a ColorSet in the xcassets folder and this is the code I was using at first to achieve this background color.
TextField("Exam title", text: $title)
.padding()
.background(Color("cardBackground"))
.cornerRadius(8)
This way I'm able to change the background color of the TextField when I'm not using it.
This is how's the outcome of this
Correct Look
The problem I'm facing is that as soon as I tap on the TextField it goes back to its default color (I think it is the default one) and I'm unable to change that.
When editing
So what I did was creating a UIViewRepresentable implementation of the TextField, maybe that could have helped me much more than SwiftUI can do at this stage.
struct CustomUIKitTextField: UIViewRepresentable {
#Binding var text: String
var placeholder: String
var backgroundColor: UIColor = .red
func makeUIView(context: UIViewRepresentableContext<CustomUIKitTextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
textField.placeholder = placeholder
textField.backgroundColor = backgroundColor
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomUIKitTextField>) {
uiView.text = text
uiView.backgroundColor = backgroundColor
uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
uiView.setContentCompressionResistancePriority(.required, for: .vertical)
}
func makeCoordinator() -> CustomUIKitTextField.Coordinator {
Coordinator(parent: self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: CustomUIKitTextField
init(parent: CustomUIKitTextField) {
self.parent = parent
}
func textFieldDidChangeSelection(_ textField: UITextField) {
parent.text = textField.text ?? ""
}
func textFieldDidBeginEditing(_ textField: UITextField) {
print("Begin editing")
textField.backgroundColor = .brown
}
func textFieldDidEndEditing(_ textField: UITextField) {
print("Finished Editing")
}
}
}
I've tried something as you can see (there are some things to just debug stuff) but I'm not that much experienced in UIKit so I don't really know what is the best way to tackle this problem and out there there's not much about this kind of problem.
Have you faced something similar before? How can I solve this problem?
EDIT:
If this can help this is the view hierarchy when the TextField is in editing mode and the selected elements that puts itself in front of the TextField is a UIFieldEditor
UIFieldEditor
first off, don't define background colour in SwiftUI:
.background(Color("cardBackground")) / remove this line of code
In the makeUIView method, setup a default background color, which is used, when user not tapping the textfield:
textfield.backgroundColor = .systemGray
Finally, use these methods in the Coordinator class to control background colour behaviour:
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.backgroundColor = .red
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
textField.backgroundColor = .systemGray
}
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)
}
is there a way to change the height of a UISearchBar's textField??
I can access the textField like this and although background color changes, nothing seems to change in terms of frame/size...
I was able to change the searchBar height in IB by setting the constraints.
But the textfield stayed the same (44)...
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.mySearchBar.layoutIfNeeded()
self.mySearchBar.layoutSubviews()
self.mySearchBar.backgroundColor = UIColor.blue
for subView in mySearchBar.subviews
{
for subsubView in subView.subviews
{
if let textField = subsubView as? UITextField
{
var currentTextFieldBounds = textField.bounds
textField.borderStyle = UITextBorderStyle.none
currentTextFieldBounds.size.height = self.mySearchBar.bounds.height-10
textField.bounds = currentTextFieldBounds
textField.backgroundColor = UIColor.red
}
}
}
The UITextField within the UISearchBar is not directly accessible. You could create your own UISearchBarsubclass to emulate a regular Search bar. You could completely customize the UI as you see fit with either Interface builder or programatically.
protocol SearchBarEventDelegate {
func searchButtonPressed(searchBar: CustomSearchBar)
func searchBarDidReceiveInput(searchText: String)
func searchBarDidBackspace(searchText: String)
}
class CustomSearchBar: UIView {
var searchTextField: UITextField?
var delegate : SearchBarEventDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(searchTextField())
}
func searchTextField() -> UITextField {
//Input custom frame and attributes here.
let textField = UITextField(frame: CGRectZero)
textField.delegate = self
return textField
}
}
extension CustomSearchBar : UITextFieldDelegate {
//Implement Textfield delegate methods here.
//Propagate events to CustomSearchBar delegate. Example Provided.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let partialSearchString = textField.text!
let fullSearchString = (partialSearchString as NSString).stringByReplacingCharactersInRange(range, withString: string)
if(range.length == 1) {
delegate?.searchBarDidBackspace(fullSearchString)
} else {
delegate?.searchBarDidReceiveInput(fullSearchString)
}
return true
}
}
When I tap on this UITextFieldmentioned on screen below, a numpad keyboard appears, the problem is that when I start tap on number, my UITextField do not update, stay with no number, only placeholder.
What I need to do?
Thanks
ADDING CODE!
#IBOutlet weak var salarioTextField: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
updateView()
salarioTextField.delegate = self
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool
{
if textField == feriasTextField
{
feriasTextField.inputView = feriasPicker
}
else if textField == salarioTextField
{
salarioTextField.keyboardType = UIKeyboardType.NumberPad
}
else if textField == inicioTextField
{
textField.inputView = datePicker
textField.inputAccessoryView = toolbar
datePicker.date = inicioDate
}
else if textField == motivoTextField
{
motivoTextField.inputView = motivoPicker
}
else
{
textField.inputView = datePicker
textField.inputAccessoryView = toolbar
datePicker.date = fimDate
}
return true
}
func textFieldDidBeginEditing(textField: UITextField)
{
backgroundScrollView.scrollEnabled = true
let scrollSize = CGSizeMake(view.frame.width, view.frame.height)
backgroundScrollView.contentSize = scrollSize
activeTextField = textField
activeTextField?.becomeFirstResponder()
}
func textFieldDidEndEditing(textField: UITextField)
{
backgroundScrollView.contentSize = CGSizeMake(0, 800)
backgroundScrollView.scrollEnabled = true
}
Please ignore the others UITextField.
Make sure you have enabled user interaction for the field.
If you implement the delegate method textViewDidBeginEditing, you can put a breakpoint or a print statement here to see if it triggers.
You can try calling becomeFirstResponder on the field.
I just figured out what was happening.
I was returning false to the method below.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return true;
}
Just changed it to true and it's working.
Thanks for your help.
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)
}