Using `textField:shouldChangeCharactersInRange:`, how do I get the text including the current typed character?
Using `textField:shouldChangeCharactersInRange:`, how do I get the text including the current typed character?
I'm using the code below to try and have textField2
's text content get updated to match textField1
's whenever the user types in textField1
.
textField2
textField1
textField1
- (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange: (NSRange)range replacementString: (NSString *)string {
if (theTextField == textField1){
[textField2 setText:[textField1 text]];
}
}
However, the output I observe is that...
textField2 is "12", when textField1 is "123"
textField2 is "123", when textField1 is "1234"
... when what I want is:
textField2 is "123", when textField1 is "123"
textField2 is "1234", when textField1 is "1234"
What am I doing wrong?
10 Answers
10
-shouldChangeCharactersInRange
gets called before text field actually changes its text, that's why you're getting old text value. To get the text after update use:
-shouldChangeCharactersInRange
[textField2 setText:[textField1.text stringByReplacingCharactersInRange:range withString:string]];
This almost worked for me. If I typed a character, this worked. If I pressed the delete button, it'd delete two characters. For me, the following suggestion worked: stackoverflow.com/questions/388237/… Basically, drag'n'drop from the UITextField into your code (to create a function), then right-click on your TextField, and drag'n'drop from the circle for the "Editing Changed" to your new function. (Sigh. I miss Visual Studio sometimes..)
– Mike Gledhill
May 12 '13 at 18:33
I also feel this is a valid answer, but not THE answer. The best way to accomplish what you want was answered by @tomute
– Pedro Borges
Sep 9 '14 at 9:08
Or textFiel.text = (textFiel.text as NSString).stringByReplacingCharactersInRange(range, withString: string) in Swift
– Max
Nov 17 '14 at 10:16
@MikeGledhill You can do the same thing programmatically:
[textField addTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]
– Steve Moser
Jun 19 '17 at 18:11
[textField addTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString * searchStr = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSLog(@"%@",searchStr);
return YES;
}
Swift 3
Based on the accepted answer, the following should work in Swift 3:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
return true
}
Both String
and NSString
have methods called replacingCharacters:inRange:withString
. However, as expected, the former expects an instance of Range
, while the latter expects an instance of NSRange
. The textField
delegate method uses an NSRange
instance, thus the use of NSString
in this case.
String
NSString
replacingCharacters:inRange:withString
Range
NSRange
textField
NSRange
NSString
replacingCharacters
should be stringByReplacingCharactersInRange
– Alan_s
Nov 7 '16 at 15:58
replacingCharacters
stringByReplacingCharactersInRange
@Alan_s I copied this snippet directly from my Xcode project and it was working fine. Are you using Xcode 8.1 with target to iOS 10.1?
– focorner
Nov 7 '16 at 17:05
Instead of using the UITextFieldDelegate, try to use "Editing Changed" event of UITextField.
Swift version for it :
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if string == " " {
return false
}
let userEnteredString = textField.text
var newString = (userEnteredString! as NSString).stringByReplacingCharactersInRange(range, withString: string) as NSString
print(newString)
return true
}
This is the code you need,
if ([textField isEqual:self.textField1])
textField2.text = [textField1.text stringByReplacingCharactersInRange:range withString:string];
use guard
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
guard case let textFieldString as NSString = textField.text where
textFieldString.stringByReplacingCharactersInRange(range, withString: string).length <= maxLength else {
return false
}
return true
}
My solution is to use UITextFieldTextDidChangeNotification
.
UITextFieldTextDidChangeNotification
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(copyText:) name:UITextFieldTextDidChangeNotification object:nil];
Don't forget to call [[NSNotificationCenter defaultCenter] removeObserver:self];
in dealloc
method.
[[NSNotificationCenter defaultCenter] removeObserver:self];
dealloc
If you need to replace the textfield text with this you can use my solution (Swift 3): https://gist.github.com/Blackjacx/2198d86442ec9b9b05c0801f4e392047
After the replacement you can just get textField.text
to retrieve the composed text.
textField.text
In Swift(4), without NSString
(pure Swift):
NSString
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let textFieldString = textField.text, let swtRange = Range(range, in: textFieldString) {
let fullString = textFieldString.replacingCharacters(in: swtRange, with: string)
print("FullString: (fullString)")
}
return true
}
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
Just a reminder it is staggeringly easier to always use the "Editing Changed" event .. just drag it in IB to a function you make.
– Fattie
Dec 10 '13 at 17:27