using rangeOfString and textfield shouldChangeCharactersInRange - the delete character? - ios

I'm using rangeofString and textfield: shouldChangeCharactersinRange: to restrict the types of keystrokes that will be valid in a textfield.
-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSString *includeString = #"1234567890-()+" ;
if ([includeString rangeOfString:string].location == NSNotFound) {
return NO;
}
return YES;
}
this works fine EXCEPT i now can't use the delete key. Any ideas how to represent the delete key to add it to the includeString?
I tried
`NSString *includeString = #"1234567890-()+\b"
but that didn't work - neither did it allow the \ or b characters to appear which i thought odd
Thanks

The replacement string string is empty when characters are deleted.
Since rangeOfString:string returns NSNotFound for an empty string,
you have to check for that situation first:
-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if ([string length] == 0)
return YES;
NSString *includeString = #"1234567890-()+" ;
if ([includeString rangeOfString:string].location == NSNotFound) {
return NO;
}
return YES;
}
Update: As #rmaddy correctly pointed out, the above method fails if more than one
character is pasted into the text field. The following method checks if all
characters of the replacement string are valid. (There are probably many solutions,
this is only one of them.)
-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
static NSString *includeString = #"1234567890-()+";
NSCharacterSet *includeSet = [NSCharacterSet characterSetWithCharactersInString:includeString];
if ([[string stringByTrimmingCharactersInSet:includeSet] length] > 0)
return NO;
return YES;
}
Note that the empty string does not need to be handled separately anymore.

Related

How to restrict UITextField to a defined set of characters and limit the length?

I am working on a login and resister view controller. I am limiting usernames to 12 characters and passwords to 16 using :
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField==self.userField){
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return !([newString length] > 12);
}
else if(textField==self.passwordField){
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return !([newString length] > 16);
}
return YES;
}
this works well but I also want to limit it to a set of characters to stop unwanted symbols and also Chinese characters. I want to define this set:
#define ACCEPTABLE_CHARACTERS #"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Not sure how to add it to the method above though and get both working. If I was to check for the character set only and not length the code would be:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
Not sure how to combine them though. Can someone help me please? Thanks!
You can do it like (I divided it to function for more readability and easy to scale the conditions)
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return ([self checkLengthOfString:newString inField:textField] && [self checkCharacter:newString]);
}
// Check Length
- (BOOL)checkLengthOfString:(NSString *)text inField:(UITextField *)textField
{
if(textField == self.userField)
{
return !([text length] > 12);
}
else if(textField == self.passwordField)
{
return !([text length] > 16);
}
}
// Check character
- (BOOL)checkCharacter:(NSString *)text
{
BOOL status = YES;
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSRange r = [text rangeOfCharacterFromSet:s];
if (r.location != NSNotFound)
{
status = NO;
}
return status;
}
Why don't you just use a regEx to match that chars?
I know this has already been answered, but I had a similar scenario and I found none of the answers on StackOverflow handled the Backspace character.
I needed to limit input into a UITextField to a specific number of AlphaNumeric characters, but be able to enter spaces.
Also, using [textField length] > kMAXNUMCHARS caused a problem: you couldn't backspace once you hit the max number of chars.
So here's my complete solution. It also disallows leading spaces. Trailing spaces are trimmed elsewhere when the value is saved (in my case to a PLIST file)
In my Constants.h file I defined:
#define ALLOWED_CHARECTERS #" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
extern const int kMAXUSERNAMELENGTH;
then in Constants.m:
const int kMAXUSERNAMELENGTH = 9;
I define my class as UITextFieldDelegate with the line
[self._txtUsername.textField setDelegate:self];
Don't forget to declare the UITextFieldDelegate protocol in your class definiion
#interface MyClass : CCNode <UITextFieldDelegate>
And finally,
//UITextFiledDelegate Protocol method
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//disallow leading spaces. must allow trailing spaces- never know if we'll add another char
//we trim trailing spaces when we save the TextField value, in our case to Plist file
if (range.location == 0 && [string isEqualToString:#" "])
return NO;
//we use defined ALLOWED_CHARECTERS so we can add chars later, easily.
//we could use [NSCharacterSet alphanumericCharacterSet] if we don't need to allow spaces
NSCharacterSet *allowedInput = [NSCharacterSet characterSetWithCharactersInString:ALLOWED_CHARECTERS];
NSArray* arChar = [string componentsSeparatedByCharactersInSet:allowedInput]; //arChar.count = 1 if 'allowedInput' not in 'string'
//disallow input if its not a backspace (replacementString paramater string equal #"" if a backspace) AND
//(disallow input >= kMAXUSERNAMELENGTH chars, OR disallow if not in allowed allowedChar set
if ( ![string isEqual:#""] && ( [textField.text length] >= kMAXUSERNAMELENGTH || !([arChar count] > 1)) )
return NO;
return YES;
}
I hope this helps someone.

UITextField auto-delete

When a user holds down the delete key for a certain amount of time, the UITextField begins deleting multiple characters at once. I'm trying to create a UITextField that has a # as the first character. This # should never be deleted. The code below works to prevent the user from deleting the # accept when the user types in many characters, and then proceeds to hold down the delete key until UITextField deletes multiple characters at once. The user is then able to delete all characters from the UITextField despite the logic below. How can this be?
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if (newLength < 1)
return NO;
else if (newString.length == 0)
return NO;
return (newLength > 30) ? NO : YES;
}
Perhaps something like this would be better:
- (void) textViewDidChange:(UITextView *)textView {
if (![textView.text hasPrefix:#"#"]) {
textView.text = [NSString stringWithFormat:#"#%#", textView.text];
}
}
This way, at any point, if your text view doesn't have a '#' as a prefix, this puts one in. Otherwise, if the user types 10 characters, then goes back and erases the '#' the system won't recognize it, or if they highlight all of the text and erase it. If later code depends on the '#' char, I'd say this is probably more reliable.
I'm not sure if the shouldChangeCharactersInRange method is technically allowed to modify the text field directly, but give this a try and let me know how it goes.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if ( newString.length > 30 )
return( NO );
if ( newString.length < 1 )
newString = #"#";
textField.text = newString; // I'll change the string myself thanks
return( NO ); // string's already changed, don't change it again
}

Calling a method on every edit of UITextField

I'm now programming a simple app that has 3 UITextFields and if I edit one, the other two should scale together with it.
I tried using
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
this method, but:
replacement string is the last character that was typed in
can't figure out how backspace works there
it is being called a little too early
if I can "fix" the first point(by sending
[NSString stringWithFormat:#"%#%#", [textField text], string];
as a parameter), it will not "fix" the second point, because string variable is:
(lldb) po string
(NSString *) $1 = 0x0080cf14 <object returned empty description>
So the question is: is there any method that is being called AFTER textFieldShouldChangeCharactersInRange:? Or is there a way to:
return YES in textFieldShouldChangeCharactersInRange: method
and THEN call a method to change the values of the 2 other UITextFields?
EDIT
I could use the following:
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
[self performSelector:#selector(myMethod:) withObject:textField afterDelay:0.1];
return YES;
}
but it doesn't seem to be the safest solution
The backspace works modifying the NSRange with a empty string. What you can do is modify the three text field in the textField:shouldChange and then return NO to the method.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string]; // this is what will happen if you return yes to this method
anotherTextField.text = // do whatever u need
yetAnotherTextField.text = // do whatever u need
return NO;
}
The following code prints correctly the full text of the text view (with the last character that was inserted), can that be useful?
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string length])
NSLog(#"Current Text:%#", [textField.text stringByAppendingString:string]);
else
NSLog(#"Current Text:%#", [textField.text substringWithRange:(NSRange){0, [textField.text length]-1}]);
return YES;
}
The backspace just sends an empty string in the string parameter.
For textFields:
[yourtextField addTarget:self action:#selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
-(void)textFieldDidChange
{
//Your Code
}

Is there anyway to limit the number of character in UITextfield to 5?

Iam trying to limit the number of character in a textfield to 5 .So when we trying to enter the 6th character it will not do anything? is that possible .I saw below code but its not working .I have searched this in google got some results like
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 5) ? NO : YES;
}
its not working am still able to add more than 5 character
Please check your delegate connection with UITextfield
Is the delegate being called? If YES, then just try this:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if ([textField.text length] > 5) {
textField.text = [textField.text substringToIndex:5-1];
return NO;
}
return YES;
}

Objective-c How to do validation on textField

I would like to prevent the user from not entering any data as well as entering only spaces. So basically there must at least be one character without a space. Then I would also like to remove any spaces at the beginning of the word so the first letter is a character that is not a space.
edit
the user must enter something and if the user enters a few spaces before it then I want to trim those spaces. I also want to prevent the user from just entering spaces.
Example
if the user enter's a name and surname like " James Dean" I would like to take the first space away but not the second space between James and Dean.
Set your UIViewController to be your destination UITextField's delegate and implement this method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// verify the text field you wanna validate
if (textField == _nameTextField) {
// do not allow the first character to be space | do not allow more than one space
if ([string isEqualToString:#" "]) {
if (!textField.text.length)
return NO;
if ([[textField.text stringByReplacingCharactersInRange:range withString:string] rangeOfString:#" "].length)
return NO;
}
// allow backspace
if ([textField.text stringByReplacingCharactersInRange:range withString:string].length < textField.text.length) {
return YES;
}
// in case you need to limit the max number of characters
if ([textField.text stringByReplacingCharactersInRange:range withString:string].length > 30) {
return NO;
}
// limit the input to only the stuff in this character set, so no emoji or cirylic or any other insane characters
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 "];
if ([string rangeOfCharacterFromSet:set].location == NSNotFound) {
return NO;
}
}
return YES;
}
try like this may be it helps to you,here is my code
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
if([text.text length]==0){
if([string isEqualToString:#" "]){
return NO;
}
}
return YES;
}
By placing this code user won't enter space as a first letter but it accepts the space in the middle of the string.
I'll give you a hint for the first part.
NSString *tempname1 = [self.textField.text stringByReplacingOccurrencesOfString:#" " withString:#""];
BOOL thereAreJustSpaces = [tempname1 isEqualToString:#""];
-(void)removeSpacesFromTextFields:(id) sender {
NSString *trim = [self.FNTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([trim length] == 0) {
self.FNTextField.text = #"";
}
}
Try this, If you want to prevent space in your text field.
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(checkSpace:) name:UITextFieldTextDidChangeNotification object:textfield];
}
-(void)checkSpace:(NSNotification *)notification
{
str = [textfield.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] ;
textfield.text=str;
}

Resources