i want to remove one last character when user presses the backspace
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.isEmpty {
print("backspace pressed")
if let itemToRemove = textField.text?.dropLast(){
let text = textField.text?.replacingOccurrences(of: itemToRemove, with: "")
textField.text = text
return true
}
}
return true
}
this function clears all the elements present in the textfield
You're using this method wrong. The delegate method is not for you to implement the change to the text, it's for you to approve the change (hence returning a bool).
From the documentation (which is always a good first point of call if something isn't working how you expect):
Return Value
true if the specified text range should be replaced;
otherwise, false to keep the old text.
Discussion
The text field calls this method whenever user actions cause its text to change. Use this
method to validate text as it is typed by the user. For example, you
could use this method to prevent the user from entering anything but
numerical values.
EDIT: (as pointed out by Duncan C in the comments, and as should have been in the original answer)
A good starting point is just to return true from this method, as then all the user input will be reflected in the text field. If you need to be more specific about what edits you allow you can introduce that logic later.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Backspace handled
guard !string.isEmpty else {
return true
}
return true
}
Related
Recently I've been working on a UITextField that hides the password while editing text on the loginPage, password field.
As everyone knows .isSecureTextEntry = true solves the problem up to a point. However, while typing the password, the last character appears and is perceived as a security hole in a way. So I could not find out a solution how to solve this. Thank you in advance for your answers.
I attached two pictures.
The solution offered by UIKIT today.
textField.isSecureTextEntry = true
It's what I wanted.
I want this
When ever you input the character the func textField(_:shouldChangeCharactersIn:replacementString:) will call to replace old text with new text. So you just need to catch the value and don't let it update by default.
textField.isSecureTextEntry = true
textField.delegate = self // add delegate to catch the action
Get the value when changing in your TextField and don't get it update the UI automatically.
extension ViewController : UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let currentText = self.textField.text as? NSString {
let newText = currentText.replacingCharacters(in: range, with: string) // change to new one
self.textField.text = newText // assign it back to textField text
return false // don't let it update automically
}
return true // by default
}
}
If you have multiple textField in the screen you must checked if the current changing is your password one before. If yes return false else return true like default.
I have a textfield population phone number. When i am entering phone number i am checking validation for a invalid phone number. i am using delegate method "textfield should change characters".It is working fine but it is not working for the first letter entered by the user.
extension phoneCell: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
validateInput(of: textField)
return true
}
Can any one help me to resolve this?
If you noticed then shouldChangeCharactersIn has a return type Bool.
What it means is that when a user presses a key on the keyboard, you'll get a callback by this delegate before even registering that character in the textfield.
Now if you return true, that pressed character will be reflected in the textfield if you return false, input will be discarded.
So for first time your string.count will be 1 but your textfeild.text.count will be 0.
Looking at your validation code I will suggest you add an IBAction on your textfeild for editing changed[here].
What does your validation function do? Why are you returning true by default?
shouldChangeCharactersIn should return the result of your validation function.
One of the UITextfield input should accept decimals. But I want to restrict the user to type only one ".", otherwise the floating point conversion gets messed up if it has more than one "." in the number. How to ensure user does not key in more than one "." as a part of decimal input?
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if ( textField == areaTextField) {
guard CharacterSet(charactersIn: "0123456789.").isSuperset(of: CharacterSet(charactersIn: string)) else {
return false
}
}
return true
}
Your approach is wrong to start with; you are way overthinking this. The computer already knows whether a string is a valid number, so just ask it. Don't examine any characters. Don't examine any keys. Simply perform the replacement described by the parameters and ask the computer if the result would be a number:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let rep = (textField.text! as NSString).replacingCharacters(in: range, with: string)
return rep.count == 0 || Double(rep) != nil
}
I'm implementing a tagging feature similar to that of Facebook. So when I type # and some character(s) after it, the function should return the word being typed.
So if the textView contains (and the cursor is at c)
Hello #Jac !
The function should return "#Jac"
If it contains (and the cursor is at a)
Hello #Ja !
Then the function should return "#Ja"
The final string of both examples would be,
Hello Jack !
I have attempted multiple solutions but none are working. One particular question was very similar to my question, but the solution has errors. Here is the link.
Update 1
Here is how I've set the delegate on the textView,
postView.textView.delegate = self
This is the code for detecting if the # character was tapped (display the friends list table, if it was)
if let text = self?.characterBeforeCursor() {
if (text == "#" && self?.friends.count != 0) {
self?.friendTableView.isHidden = false
} else {
var word // Need to get the word being typed
self?.displayedFriends = (self?.displayedFriends.filter { ($0["firstName"]?.hasPrefix(word))! })!
}
}
Update 2
The solution below did not solve the problem. It is returning all text in the textfield instead of just the word that is being typed.
There is a delegate function called shouldChangeCharactersInRange. From there you can get the current text after the user tapped the letter.
Make sure you use UITextFieldDelegate in your class declaration and set the textField's delegate to self.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//get the updated text from the text field like this:
let text = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
//note that we *need* to use the text as NSString, because the delegate method gives us an NSRange, rather than a Range which we can't use on String, but NSString, so we need to convert that first
return true //so the text is visually updated in the textfield
}
Edit
I just saw that you posted about UITextView. It's pretty much the same:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let text = (textView.text as NSString?)?.replacingCharacters(in: range, with: text)
return true
}
Edit 2
You need to also assign the text view's text to your variable in the code snippet you provided:
} else {
var word = postView.textView.text
self?.displayedFriends = (self?.displayedFriends.filter { ($0["firstName"]?.hasPrefix(word))! })!
}
For a UITextField, what is the best way to detect if the user is typing and the textfield has a value?
I've tried the following unsuccessfully:
Value Changed: no response
Editing Did End: no response
Touch Up Inside: doesn't trigger until after the user clicks out of the textfield
Try using the shouldChangeCharactersInRange event.
func textField(textField: UITextField,
shouldChangeCharactersInRange range: NSRange,
replacementString string: String)
-> Bool {
// Put your code here
}
This is called whenever a user adds or removes a new character to your UITextField.
If you want to accept the change, return true. Otherwise return false.
Just make sure your UITextField conforms to the UITextFieldDelegate Protocol