I have a UITextField where in I am restricting entering more than 2 digits. Now, it works fine but when I tap on the text field & select all the content & then type it does not allow me to over-write the existing 2 digits.
Any clue on how to use 'selectedTextRange' property here?
- (BOOL)cell:(RunnerTableViewCell *)iCell shouldChangeCharactersInRange:(NSRange)iRange replacementString:(NSString *)iString {
self.navigationItem.rightBarButtonItem.enabled = YES;
NSCharacterSet *anUnacceptedInput = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
int aCharacterUpperLimit = 2;
BOOL aReturnValue = YES;
NSInteger aTotalLength = iCell.inputField.text.length + [iString length];
NSLog(#"iString=%# aTotalLength=%d",iString,aTotalLength);
if ([[iString componentsSeparatedByCharactersInSet:anUnacceptedInput] count] > 1 || (aTotalLength > aCharacterUpperLimit && ![iString isEqualToString:kRunnerEmptyString]) || [iString length] > aCharacterUpperLimit) {
aReturnValue = NO;
}
return aReturnValue;
}
Try this:
NSInteger aTotalLength = iCell.inputField.text.length + [iString length] - iRange.length;
Related
I am getting Phone card number form user in UI text field. The format of number is like
123-4567-890
I want that as user types 123 automatically - is inserted in UITextField same after 4567 - and so on.
I Did it using following code in UITextField delegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
{
NSLog(#"***** %d",textField.text.length);
if(textField.text.length == 3)
{
textField.text = [textField.text stringByAppendingString:#"-"];
}
return YES;
}
But the Problem raised while clear the text, When we start clearing.
Last 3 digits 890 clears and then - addded, we cleared it and again added and soooo on so clearing stop at
We clear all the text at a time using
textField.clearButtonMode = UITextFieldViewModeWhileEditing; //To clear all text at a time
But our requirement is user must delete one character at a time.
How to achieve it?
During clearing replacementString should be empty #"". So replacement string should be checked also in addition to length check. Like this:
if (textField.text.length == 3 && ![string isEqualToString:#""]) {
// append -
}
USE: I have seen this somewhere in this forum, It worked for me
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *filter = #"###-####-###";
if(!filter) return YES;
NSString *changedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if(range.length == 1 && string.length < range.length && [[textField.text substringWithRange:range] rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:#"0123456789"]].location == NSNotFound)
{
NSInteger location = changedString.length-1;
if(location > 0)
{
for(; location > 0; location--)
{
if(isdigit([changedString characterAtIndex:location]))
break;
}
changedString = [changedString substringToIndex:location];
}
}
textField.text = filteredStringFromStringWithFilter(changedString, filter);
return NO;
}
NSString *filteredStringFromStringWithFilter(NSString *string, NSString *filter)
{
NSUInteger onOriginal = 0, onFilter = 0, onOutput = 0;
char outputString[([filter length])];
BOOL done = NO;
while(onFilter < [filter length] && !done)
{
char filterChar = [filter characterAtIndex:onFilter];
char originalChar = onOriginal >= string.length ? '\0' : [string characterAtIndex:onOriginal];
switch (filterChar) {
case '#':
if(originalChar=='\0')
{
done = YES;
break;
}
if(isdigit(originalChar))
{
outputString[onOutput] = originalChar;
onOriginal++;
onFilter++;
onOutput++;
}
else
{
onOriginal++;
}
break;
default:
outputString[onOutput] = filterChar;
onOutput++;
onFilter++;
if(originalChar == filterChar)
onOriginal++;
break;
}
}
outputString[onOutput] = '\0';
return [NSString stringWithUTF8String:outputString];
}
I have an integer value that spans a range so large it is impractical to use a slider, as it lacks the sensitivity to pick out an exact value in that range.
I used a PSTextFieldSpecifier instead, and set the keyboard to Numbers. However, in Settings.app, the copy and paste function allows text to be inserted into what should be a numeric field.
Does anyone have a solution to the problem?
I have always implemented this with a custom
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
routine. You monitor the characters as they come in and only accept the numerics.
I used a UITextField, and implemented the UITextFieldDelegate methods outlined below:
// This method enforces the textField to give up first responder and return
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
// This method copies the current UITextField' text into a string used for editing
// comparing, and for if a cancelation occurs we can replace with the original text
-(void)textFieldDidBeginEditing:(UITextField *)textField{
initialValueWhenEntering = [NSString stringWithString:textField.text];
[initialValueWhenEntering retain];
}
// This routine enforces that only a single period or numerics be taken into the new
// value for the input
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
unsigned int stringLength = (unsigned int)[textField.text lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
unsigned int counter;
unsigned int periodCounter = 0;
// Test to make sure there wasnt already some periods in the initial string
for(counter = 0; counter < stringLength; counter++){
if( [textField.text characterAtIndex:(NSUInteger)counter] != '.' &&
( [textField.text characterAtIndex:(NSUInteger)counter] < '0' ||
[textField.text characterAtIndex:(NSUInteger)counter] > '9' ) ){
return NO;
}else if( [textField.text characterAtIndex:(NSUInteger)counter] == '.' ){
periodCounter++;
}
}
stringLength = (unsigned int)[string lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
for(counter = 0; counter < stringLength; counter++){
if( [string characterAtIndex:(NSUInteger)counter] != '.' &&
( [string characterAtIndex:(NSUInteger)counter] < '0' || [string characterAtIndex:(NSUInteger)counter] > '9' ) ){
return NO;
}else if( [string characterAtIndex:(NSUInteger)counter] == '.' ){
periodCounter++;
}
}
if( periodCounter <= 1 ){
return YES;
}else{
return NO;
}
}
And finally the routine that gets automatically called when the textfield has ended editing
-(void)textFieldDidEndEditing:(UITextField *)textField{
unsigned int stringLength = (unsigned int)[textField.text
lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
unsigned int counter;
if( 0 == stringLength ){
textField.text = initialValueWhenEntering;
float temperature = [textField.text floatValue];
// Set the temperature of all element boxes
for(counter = MIN_ELEMENT_INDEX; counter <= MAX_ELEMENT_INDEX; counter++){
[periodicButtons[counter] setOutputType:myGraphType aValue:temperature];
}
}else if( 1 == stringLength ){
if( [textField.text characterAtIndex:(NSUInteger)0] == '.' ){
textField.text = initialValueWhenEntering;
}
float temperature = [textField.text floatValue];
textField.text = [NSString stringWithFormat:#"%.2f", temperature];
// Set the temperature of all element boxes
for(counter = MIN_ELEMENT_INDEX; counter <= MAX_ELEMENT_INDEX; counter++){
[periodicButtons[counter] setOutputType:myGraphType aValue:temperature];
}
}else{ // Should be a semi-valid number at this point
float temperature = [textField.text floatValue];
if( temperature > 5900.0 ){
temperature = 5900.0;
}
textField.text = [NSString stringWithFormat:#"%.2f", temperature];
// Set the temperature of all element boxes
for(counter = MIN_ELEMENT_INDEX; counter <= MAX_ELEMENT_INDEX; counter++){
[periodicButtons[counter] setOutputType:myGraphType aValue:temperature];
}
}
[initialValueWhenEntering release];
}
In my example, I did perform value limit checking, but this code could be deleted.
I have been working on this for a few days now and I have some buzzy things going on with my textfields... and it's got to the point where I need to take a step back and hope someone with a fresh pair of eyes can shed light on the situation.
basically what I'm doing is formatting a 20 character string into sets of 5 as the user types after every 5th character a hyphen pops into the string, that works sweet.
I have a submit button that is not perusable until the 20th character is entered, this also works but where it gets CRAZY! is if you delete back one character the submit button still works.. then you delete back one more character and it doesn't work... I'm at a loss as my if statements conditions don't work like they should I specify == 23 characters and you have to hit one of the keys 24 times to get into that statement.. it makes no logical sense.
anyway if you could help me with the first question that would be great then if you have any ideas on the second question that would be great.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *separator = #"-";
int seperatorInterval = 5; //how many chars between each hyphen
NSString *originalString = [regTextField.text stringByReplacingOccurrencesOfString:separator withString:#""];
if (textField.text.length == 23 && range.length == 0){
return NO; // return NO to not change text
}
if (![originalString isEqualToString:#""] && ![string isEqualToString:#""]) {
NSString *lastChar = [regTextField.text substringFromIndex:[regTextField.text length] - 1];
int modulus = [originalString length] % seperatorInterval;
if (![lastChar isEqualToString:separator] && modulus == 0) {
regTextField.text = [regTextField.text stringByAppendingString:separator];
}
}
[self validateTextFields];
return YES; //Keep accepting input from the user
}
//Validating text field to see if Submit button can be pressed or not
-(IBAction) validateTextFields {
NSString *intString = [NSString stringWithFormat:#"%d", regTextField.text.length];
NSLog(#"Starting %#", intString);
if (regTextField.text.length < 22){
[submitButton setEnabled:NO]; //enables submitButton
}
else {
regTextField.text = [regTextField.text substringToIndex:22];
[submitButton setEnabled:YES]; //disables submitButton
}
intString = [NSString stringWithFormat:#"%d", regTextField.text.length];
NSLog(#"Done %#", intString);
}
You need to add = sign in this if statement
if (regTextField.text.length <= 22){
or just change the number to 23 either way it should work
if (regTextField.text.length < 23){
i need to enter mobile number in a text field.
i need to display mobile number like this format 123-456-7890.
for eg: 1234567890 is my mobile number,while am entering this mobile number in text field,
for first 3 digits i need to place -,after 3 digits again i need to place -.
if i enter 123 then automatically place - in text field,after 456 place ,no need of placing for further 4 digits.
similar to displaying text in currency format.
but while getting text from that text field i need to get mobile number no need of - like 1234567890,not 123-456-7890.
i think my question is quite clear now,let me add comment if is not.
Thank u in advance.
Just to clarify: As a user enters a phone number into a UITextField, you would like it to automatically insert dashes in the proper places.
The answer is in using the UITextFieldDelegate protocol.
1) Set your controller object as a delegate for the UITextField.
2) You'll find the following method in the protocol:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
This method is called every time a character change occurs in the text field.
3) How robust you want your implementation to be is up to you. You could simply do a count of the current characters and insert dashes after 3 and 6 characters. It would be wise to also reject any non-numeric characters.
Here is a sample implementation. We basically take over the field editing manually - Inserting dashes after the appropriate string lengths and making sure the user can only enter numbers:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *numSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789-"];
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
int charCount = [newString length];
if ([newString rangeOfCharacterFromSet:[numSet invertedSet]].location != NSNotFound
|| [string rangeOfString:#"-"].location != NSNotFound
|| charCount > 12) {
return NO;
}
if (charCount == 3 || charCount == 7) {
newString = [newString stringByAppendingString:#"-"];
}
textField.text = newString;
return NO;
}
Updated Matthew McGoogan's code : This works fine with back space also..
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (textField.tag == 8) {
NSCharacterSet *numSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789-"];
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
int charCount = [newString length];
if (charCount == 3 || charCount == 7) {
if ([string isEqualToString:#""]){
return YES;
}else{
newString = [newString stringByAppendingString:#"-"];
}
}
if (charCount == 4 || charCount == 8) {
if (![string isEqualToString:#"-"]){
newString = [newString substringToIndex:[newString length]-1];
newString = [newString stringByAppendingString:#"-"];
}
}
if ([newString rangeOfCharacterFromSet:[numSet invertedSet]].location != NSNotFound
|| [string rangeOfString:#"-"].location != NSNotFound
|| charCount > 12) {
return NO;
}
textField.text = newString;
return NO;
}
return YES;}
I used Matthews post above as a base.
This will format as so: (444) 444-4444
It also handles backspaces, unlike the answer above.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if(textField == _txtPhone1 || textField == _txtPhone2 || textField == _txtPhone3 || textField == _txtPhone4)
{
NSCharacterSet *numSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789-() "];
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
int charCount = [newString length];
if ([newString rangeOfCharacterFromSet:[numSet invertedSet]].location != NSNotFound
|| [string rangeOfString:#")"].location != NSNotFound
|| [string rangeOfString:#"("].location != NSNotFound
|| [string rangeOfString:#"-"].location != NSNotFound
|| charCount > 14) {
return NO;
}
if (![string isEqualToString:#""])
{
if (charCount == 1)
{
newString = [NSString stringWithFormat:#"(%#", newString];
}
else if(charCount == 4)
{
newString = [newString stringByAppendingString:#") "];
}
else if(charCount == 5)
{
newString = [NSString stringWithFormat:#"%#) %#", [newString substringToIndex:4], [newString substringFromIndex:4]];
}
else if(charCount == 6)
{
newString = [NSString stringWithFormat:#"%# %#", [newString substringToIndex:5], [newString substringFromIndex:5]];
}
else if (charCount == 9)
{
newString = [newString stringByAppendingString:#"-"];
}
else if(charCount == 10)
{
newString = [NSString stringWithFormat:#"%#-%#", [newString substringToIndex:9], [newString substringFromIndex:9]];
}
}
textField.text = newString;
return NO;
}
}
Use
NSString* number = [textField.text stringByReplacingOccurrencesOfString: #"-" withString: #""];
I have 4 text fields in my application.
I validate my textfields as textfield allow 0,1,...9 and .,for that i write code as fallows
- (IBAction) textfield:(id)sender {
if ([textfield.text length] > 0) {
if ([textfield.text length] > 10){
textfield.text = [textfield.text substringWithRange:NSMakeRange(0, 10)];
}
else {
//retrieve last character input from texfield
int I01 = [homevalue.text length];
int Char01 = [homevalue.text characterAtIndex:I01-1];
//check and accept input if last character is a number from 0 to 9
if ( (Char01 < 46) || (Char01 > 57) || (Char01 == 47) ) {
if (I01 == 1) {
textfield.text = nil;
}
else {
textfield.text = [homevalue.text substringWithRange:NSMakeRange(0, I01-1)];
}
}
}
}
}
It works fine, Now i need to validate that . allows only once with in the textfield.
eg: 123.45
According to my code if i place again . it is allowed.
eg:123.45.678
But it wont allowed once i place . ,that textfield wont allowed.
ed:123.45678.
How can i done this,
can any one pls help me.
Thank u in advance.
Try this predicate for texts that start with a number like "23.67"
NSString *decimalRegex = #"[0-9]+([.]([0-9]+)?)?"; // #"[0-9]+[.][0-9]+";
NSPredicate *decimalTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", decimalRegex];
BOOL isValidDecimal = [decimalTest evaluateWithObject:[textField text]];
If you want to allow "." at the fist place like ".95" use the following regex,
NSString *decimalRegex = #"[0-9]*([.]([0-9]+)?)?"; //#"[0-9]*[.][0-9]+";
Your code should look like this,
- (IBAction)textfield:(id)sender {
int textLength = [[textfield text] length];
if (textLength > 0) {
NSString *decimalRegex = #"[0-9]+([.]([0-9]+)?)?"; //#"[0-9]+[.][0-9]+";
NSPredicate *decimalTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", decimalRegex];
BOOL isValidDecimal = [decimalTest evaluateWithObject:[textField text]];
if (!isValidDecimal) {
NSString *text = [[textField text] substringToIndex:textLength - 1];
[textfield setText:text]
}
}
}
I guess this should work! Give it a try!
Well you can use this method
- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet options:(NSStringCompareOptions)mask range:(NSRange)aRange
on textfield.text as its a NSString only