I have something generic, which also works with phone, using mask. So, I have a subclass of UITextField
that I called CustomTextField
. My .h
file looks something like this:
@interface CustomTextField : UITextField
@property (nonatomic, retain) NSString *mask;
- (BOOL)shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
@end
And in my implementation file .m
, like this:
NSString *filteredFromStringWithFilter(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 ? '- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
return [(CustomTextField *)textField shouldChangeCharactersInRange:range replacementString:string];
}
' : [string characterAtIndex:onOriginal];
switch (filterChar) {
case '#':
if (originalChar=='@interface CustomTextField : UITextField
@property (nonatomic, retain) NSString *mask;
- (BOOL)shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
@end
') {
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] = 'NSString *filteredFromStringWithFilter(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 ? '- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
return [(CustomTextField *)textField shouldChangeCharactersInRange:range replacementString:string];
}
' : [string characterAtIndex:onOriginal];
switch (filterChar) {
case '#':
if (originalChar=='%pre%') {
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] = '%pre%'; // Cap the output string
return [NSString stringWithUTF8String:outputString];
}
- (BOOL)shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (self.mask) {
NSString *changedString = [self.text stringByReplacingCharactersInRange:range withString:string];
if (range.length == 1 && // Only do for single deletes
string.length < range.length &&
[[self.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];
}
}
[self setText:filteredFromStringWithFilter(changedString, self.mask)];
return NO;
}
return YES;
}
'; // Cap the output string
return [NSString stringWithUTF8String:outputString];
}
- (BOOL)shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (self.mask) {
NSString *changedString = [self.text stringByReplacingCharactersInRange:range withString:string];
if (range.length == 1 && // Only do for single deletes
string.length < range.length &&
[[self.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];
}
}
[self setText:filteredFromStringWithFilter(changedString, self.mask)];
return NO;
}
return YES;
}
And in my ViewController
:
%pre%
Ready, so it's generic to use the mask you want, for example, using the interface: