Restricting the number of characters entered in UiTextfield by user - ios

I am trying to restrict the number of characters entered in UITextfied,I want the user to enter the numbers in range 40.[0 to 9] to 250.[0 to 9] and the user can only one digit after the decimal point and also he cant enter multiple decimal points. I hope I have made my point clear, so far I have tried some code which is below
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789."] invertedSet];
// allow backspace
if (range.length > 0 && [string length] == 0) {
return YES;
}
// do not allow . at the beggining
if (range.location == 0 && [string isEqualToString:#"."]) {
return NO;
}
// set the text field value manually
NSString *newValue = [[textField text] stringByReplacingCharactersInRange:range withString:string];
newValue = [[newValue componentsSeparatedByCharactersInSet:nonNumberSet] componentsJoinedByString:#""];
textField.text = newValue;
// return NO because we're manually setting the value
return NO;
}
So friends please help me further.
Regards
Ranjit

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.

Adding a constant country code at beginning of UITextField

I have a UITextField that the user require to enter a phone number into it.
This is how it looks like right now:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// Auto-add hyphen before appending 4rd or 7th digit
//
//
if (range.length == 0 && (range.location == 3 || range.location == 7))
{
textField.text = [NSString stringWithFormat:#"%#-%#", textField.text, string];
return NO;
}
// Delete hyphen when deleting its trailing digit
//
//
if (range.length == 1 && (range.location == 4 || range.location == 8))
{
range.location--;
range.length = 2;
textField.text = [textField.text stringByReplacingCharactersInRange:range withString:#""];
return NO;
}
// Prevent crashing undo bug – see note below.
//
//
if (range.length + range.location > textField.text.length)
{
return NO;
}
// Limit text field characters
//
//
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 12) ? NO : YES;
}
After the 3rd digit, I'm adding a hyphen and than again. What I'm trying to achieve here is to add a country code as constant at start of the UITextField and that the user will not be able to remove it. Lets say USA country code, then the UITextField text will look like that at start +1- and then after writing the full number it will look like that: +1-600-242-252
How can I do that?
Thanks in advance!
This answer assumes a starting country code string which includes the hyphen at the end, ex: self.countryCode = #"+1-";. The text field should initially contain "+1-".
I've made my answer way more comprehensive than your original intent because it handles many use cases you've overlooked, for example copy and paste operations with multiple characters, inappropriate hyphen deletion, inappropriate hyphen addition, mid-line insertion, etc. It's still not perfect though because your original answer was unspecific in some ways... For example, if you specify that the user should only be able to enter digits, the code can be much cleaner.
The below implementation is described line by line in the comments included throughout.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// Combine the new text with the old
NSMutableString *combinedText = [[textField.text stringByReplacingCharactersInRange:range withString:[NSString stringWithFormat:#"%#", string]] mutableCopy];
// If the user deletes part of the country code or tries
// to edit it in any way, don't allow it
if (combinedText.length < self.countryCode.length ||
![combinedText hasPrefix:self.countryCode]) {
return NO;
}
// Limit text field characters to 12
if (combinedText.length > self.countryCode.length + 12) {
return NO;
}
// If the user tries to add a hyphen where there's supposed
// to be a hyphen, allow them to do so.
if ([string isEqualToString:#"-"] &&
(range.location == self.countryCode.length + 3 ||
range.location == self.countryCode.length + 7)) {
return YES;
}
// Remove all the hyphens other than the one directly
// following the country code
[combinedText replaceOccurrencesOfString:#"-" withString:#"" options:0 range:NSMakeRange(self.countryCode.length, [combinedText length] - self.countryCode.length)];
// Auto-add the hyphens before the 4th and 7th digits
if (combinedText.length > self.countryCode.length + 3)
[combinedText insertString:#"-" atIndex:self.countryCode.length + 3];
if (combinedText.length > self.countryCode.length + 7)
[combinedText insertString:#"-" atIndex:self.countryCode.length + 7];
// Store the original cursor position
UITextPosition *pos = [textField selectedTextRange].start;
// Count up the original number of hyphens
NSUInteger originalNumberOfHyphens = [[textField.text componentsSeparatedByString:#"-"] count] - 1;
// Count up the new number of hyphens
NSUInteger newNumberOfHyphens = [[combinedText componentsSeparatedByString:#"-"] count] - 1;
// Create a cursor offset to reflect the difference
// in the number of hyphens
float offset = newNumberOfHyphens - originalNumberOfHyphens;
// Update the text field to contain the combined text
textField.text = combinedText;
// Update the cursor position appropriately
if (string.length > 0) {
UITextPosition* cursor = [textField positionFromPosition:[textField beginningOfDocument] offset:range.location + range.length + offset + string.length];
textField.selectedTextRange = [textField textRangeFromPosition:cursor toPosition:cursor];
} else {
UITextPosition* cursor = [textField positionFromPosition:pos inDirection:UITextLayoutDirectionLeft offset:1-offset];
textField.selectedTextRange = [textField textRangeFromPosition:cursor toPosition:cursor];
}
// No need to replace the string since it's already been done
return NO;
}
To keep a constant at the beginning, you basically want to check if the constant still exist in the proposed text. If it doesn't reject such edits.
You should not try to insert hyphens at specific editing steps. It's better to manipulate the whole string.
E.g.
test if string could be valid. i.e. starts with +1
remove all hyphens you previously added
reinsert all hyphens
In code this would look like this:
- (void)viewDidLoad {
[super viewDidLoad];
self.textField.text = #"+1"; // start with a +1 in the textField otherwise we can't change the field at all
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *proposedText = [textField.text stringByReplacingCharactersInRange:range withString:string];
if (![proposedText hasPrefix:#"+1"]) {
// tried to remove the first +1
return NO;
}
NSString *formattedPhoneNumber = [proposedText substringFromIndex:2]; // without +1 prefix
NSString *unformattedPhoneNumber = [formattedPhoneNumber stringByReplacingOccurrencesOfString:#"-" withString:#""]; // without hypens
// start with the prefix
NSMutableString *newText = [NSMutableString stringWithString:#"+1"];
for (NSInteger i = 0; i < [unformattedPhoneNumber length]; i++) {
if (i % 3 == 0) {
// add a - every 3 characters. add one at the beginning as well
[newText appendString:#"-"];
}
// add each digit from the unformatted phonenumber
[newText appendString:[unformattedPhoneNumber substringWithRange:NSMakeRange(i, 1)]];
}
textField.text = newText;
return NO;
}
This is still a very naive implementation. It has a couple of problems, for example the cursor will always be at the end because we set text of the textField manually. So the user can't easily remove numbers in the middle of the string. Of course there are ways around this. selectedTextRange would be the property to use. And you can't really paste phone numbers into the field. And of course the user can't delete a hyphen.
Formatting while the user is typing tends to get complicated quickly because there are so many edge cases. But that should get you started.

Unable to use backspace key to delete a character from a textfield in iOS

I am implementing the following delegate method for UITextField:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *integerPart = [textField.text componentsSeparatedByString:#"."][0];
NSString *decimalPart = [textField.text componentsSeparatedByString:#"."][1];
if ([integerPart length] > 8 || [decimalPart length] > 5) {
return NO;//this clause is always called.
}
...
}
I am trying to limit the number of digits entered in the textField to 6. The problem I have is that if I enter a number with 6 digits after the decimal, and then try to press the backspace key on my device to delete the numbers, or need to make a correction inside the number, I'm unable to.
The reason is that whenever it comes to this point in my code, it notices that I have already entered 6 digits after the decimal (which is correct), and thus, nullifies my backspace key entry. How do I maintain this limit of 6 digits after the decimal place, AND allow for editing of the number after reaching this limit?
I haven't had a chance to test this, but according to this answer, string should be empty when a backspace is entered (which makes sense). So you should be able to do this.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Always allow a backspace
if ([string isEqualToString:#""]) {
return YES;
}
// Otherwise check lengths
NSString *integerPart = [textField.text componentsSeparatedByString:#"."][0];
NSString *decimalPart = [textField.text componentsSeparatedByString:#"."][1];
if ([integerPart length] > 8 || [decimalPart length] > 5) {
return NO;//this clause is always called.
}
return YES;
}
//Construct the new string with new input
NSString* newText = [textField.text stringByReplacingCharactersInRange:range
withString:text];
NSString *integerPart = [newText componentsSeparatedByString:#"."][0];
NSString *decimalPart = [newText componentsSeparatedByString:#"."][1];
if ([integerPart length] > 8 || [decimalPart length] > 5) {
return NO;//this clause is always called.
}
I believe this is what you need. This will construct the new string that will be displayed in the textfield and you can evaluate that string.

How to insert a string automatically while user editing UITEXTFIELD

I want to my uitextfield be like XXX.XXX.XXX/XX at the end of typing.
To limit the lenght I use this:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == _cpfField) {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:NUMBERS_ONLY] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return (([string isEqualToString:filtered])&&(newLength <= CHARACTER_LIMIT));
} else{
return YES;
}
}
The problem is how to insert the "." and "/" while user still editing it.
The following code should do the following:
Limit the number of characters that can be typed/pasted into the text field
Automatically add periods and slashes at the appropriate locations
Prevent issues from the user copy/pasting a string that already has the necessary periods/slashes
That said, there is almost certainly more efficient ways to do this; but if you're not concerned about code length it'll do the trick just fine.
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *text = textField.text;
// If we're trying to add more than the max amount of characters, don't allow it
if ([text length] == 14 && range.location > 13) {
return NO;
}
// First lets add the whole string we're going for
text = [text stringByReplacingCharactersInRange:range withString:string];
// Now remove spaces, periods, and slashes (since we'll add these automatically in a minute)
text = [text stringByReplacingOccurrencesOfString:#" " withString:#""];
text = [text stringByReplacingOccurrencesOfString:#"." withString:#""];
text = [text stringByReplacingOccurrencesOfString:#"/" withString:#""];
// We need to use an NSMutableString to do insertString calls in a moment
NSMutableString *mutableText = [text mutableCopy];
// Every 4th char will be a '.', but we don't want to check more than the first 8 characters
for (NSUInteger i = 3; i < mutableText.length && i < 8; i += 4) {
[mutableText insertString:#"." atIndex:i];
}
// If the text is more than 11 characters, we also want to insert a '/' at the 11th character index
if (mutableText.length > 11) {
[mutableText insertString:#"/" atIndex:11];
}
// lets set text to our new string
text = mutableText;
// Now, lets check if we need to cut off extra characters (like if the person pasted a too-long string)
if (text.length > 14) {
text = [text stringByReplacingCharactersInRange:NSMakeRange(14, mutableText.length-14) withString:#""];
}
// Finally, set the textfield to our newly modified string!
textField.text = text;
return NO;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *text = textField.text;
text = [text stringByReplacingCharactersInRange:range withString:string];
text = [text stringByReplacingOccurrencesOfString:#"." withString:#""];
// Do your length checking here
NSMutableString *mutableText = [text mutableCopy];
// Every 4th char will be a .
for (NSUInteger i = 3; i < mutableText.length; i += 4) {
[mutableText insertString:#"." atIndex:i];
}
textField.text = mutableText;
return NO;
}
UK National Insurance Number Text Field
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == _txtNationalInsuranceNumber) {
NSString *text = textField.text;
// If we're trying to add more than the max amount of characters, don't allow it
if ([text length] == 13 && range.location > 12) {
return NO;
}
// First lets add the whole string we're going for
text = [text stringByReplacingCharactersInRange:range withString:string];
// Now remove spaces, periods, and slashes (since we'll add these automatically in a minute)
text = [text stringByReplacingOccurrencesOfString:#" " withString:#""];
// We need to use an NSMutableString to do insertString calls in a moment
NSMutableString *mutableText = [text mutableCopy];
// Every 4th char will be a '.', but we don't want to check more than the first 8 characters
for (NSUInteger i = 2; i < mutableText.length && i < 10; i += 3) {
[mutableText insertString:#" " atIndex:i];
}
// If the text is more than 11 characters, we also want to insert a '/' at the 11th character index
if (mutableText.length > 11) {
[mutableText insertString:#" " atIndex:11];
}
// lets set text to our new string
text = mutableText;
// Now, lets check if we need to cut off extra characters (like if the person pasted a too-long string)
if (text.length > 14) {
text = [text stringByReplacingCharactersInRange:NSMakeRange(14, mutableText.length-14) withString:#""];
}
// Finally, set the textfield to our newly modified string!
textField.text = text;
return NO;
}
else
{
return YES;
}
}

Appending the decimal automatically while typing in the UITextField

I am having a UITextField in which I had limited the number of characters to 4 before decimal and 3 to after decimal. I have done this through
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
if (textField == txt_weightKg)
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range
withString:string];
NSString *expression = #"^([0-9]{1,4}+)?(\\.([0-9]{1,3})?)?$";
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:expression
options:NSRegularExpressionCaseInsensitive
error:nil];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString
options:0
range:NSMakeRange(0,
[newString length])];
if (numberOfMatches == 0)
return NO;
}
return YES;
}
This is only for keeping the validation but now I want i actually want is that As soon as I start typing in the UITextfield a decimal is automatically appended with the number. The second condition is that as I reaches the 4 digits the next digit should be after the decimal. For example:-
if I entered 1 it should look like 1. , for 2 digits 11. this has to continue up to 4 digits and then as soon as I eneter the fifth digit it should place that 5th digit after the decimal as 1111.1 which will continue to 3 places after decimal.
If somebody can help me then It will be greatly appreciated! feel free to ask in case of confusion.
I think i achieved what you required by following code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//create character set containing numbers only
NSCharacterSet * set = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789"] invertedSet];
if (textField.text.length >= 8 && range.length == 0)
{
return NO;
}
else
{
if ([string rangeOfCharacterFromSet:set].location != NSNotFound) {
return NO;
}
else
{
int length = [textField.text length];
//append a decimal after 4 digits
if([textField.text length] ==4 && string.length != 0)
{
textField.text = [NSString stringWithFormat:#"%#.",textField.text];
}
return YES;
}
}
}
Please confirm your response to this.

Resources