在开发的过程中,为了使产品美观,和数据易读。我们经常会接到这样的需求,比如:在用户输入手机号码的地方自动空格,在TextField框里面自动生成手机号码的格式, 类似与这样的需求还有身份证格式和银行卡格式!
这个需求的难点在于,在输入的时候在合适的位置添加空格和在删除的时候也一并把空格删除掉!
在这里我写了一个UITextField的分类,来实现手机号;银行卡,以及身份证号码输入的时候进行格式化:
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, HBTextFieldFormatType) {
kHBTextFieldTypeFormatUnkown = 0, // 未知
kHBTextFieldTypeFormatBankCard, // 银行卡号格式
kHBTextFieldTypeFormatPhoneNO, // 手机号码格式
kHBTextFieldTypeFormatIDNO, // 身份证号码格式
};
@interface UITextField (Format)
@property (nonatomic, assign) HBTextFieldFormatType textFormatType;
@end
.m文件的实现:
#import "UITextField+Format.h"
#import <objc/runtime.h>
static NSString *formatType = @"formatType";
@implementation UITextField (Format)
@dynamic textFormatType;
- (void)setTextFormatType:(HBTextFieldFormatType)textFormatType{
objc_setAssociatedObject(self,&formatType,@(textFormatType),OBJC_ASSOCIATION_COPY);
[self addTarget:self action:@selector(reformatAsBankNumber:) forControlEvents:UIControlEventEditingChanged];
}
- (HBTextFieldFormatType )textFormatType{
NSString *textFormatType = (NSString *)objc_getAssociatedObject(self, &formatType);
return [textFormatType integerValue];
}
-(void)reformatAsBankNumber:(UITextField *)textField {
/**
* 判断正确的光标位置
*/
NSUInteger targetCursorPostion = [textField offsetFromPosition:textField.beginningOfDocument toPosition:textField.selectedTextRange.start];
NSString *numberWithoutSpaces = [self removeNonDigits:textField.text andPreserveCursorPosition:&targetCursorPostion];
NSString *numberWithSpaces;
if(self.textFormatType == kHBTextFieldTypeFormatBankCard){
numberWithSpaces = [self insertSpacesEveryFourDigitsIntoString:numberWithoutSpaces andPreserveCursorPosition:&targetCursorPostion];
}else if (self.textFormatType == kHBTextFieldTypeFormatPhoneNO){
numberWithSpaces = [self insertSpacesIntoPhoneNumberString:numberWithoutSpaces andPreserveCursorPosition:&targetCursorPostion];
}else if (self.textFormatType == kHBTextFieldTypeFormatIDNO){
numberWithSpaces = [self insertSpacesIntoIDNOString:numberWithoutSpaces andPreserveCursorPosition:&targetCursorPostion];
}
textField.text = numberWithSpaces;
UITextPosition *targetPostion = [textField positionFromPosition:textField.beginningOfDocument offset:targetCursorPostion];
[textField setSelectedTextRange:[textField textRangeFromPosition:targetPostion toPosition:targetPostion]];
}
/**
* 除去非数字字符,确定光标正确位置
*
* @param string 当前的string
* @param cursorPosition 光标位置
*
* @return 处理过后的string
*/
- (NSString *)removeNonDigits:(NSString *)string andPreserveCursorPosition:(NSUInteger *)cursorPosition {
NSUInteger originalCursorPosition =*cursorPosition;
NSMutableString *digitsOnlyString = [NSMutableString new];
for (NSUInteger i=0; i<string.length; i++) {
unichar characterToAdd = [string characterAtIndex:i];
if(isdigit(characterToAdd)) {
NSString *stringToAdd = [NSString stringWithCharacters:&characterToAdd length:1];
[digitsOnlyString appendString:stringToAdd];
}
else {
if(i<originalCursorPosition) {
(*cursorPosition)--;
}
}
}
return digitsOnlyString;
}
#pragma 银行卡格式
/**
* 将空格插入我们现在的string 中,并确定我们光标的正确位置,防止在空格中
*
* @param string 当前的string
* @param cursorPosition 光标位置
*
* @return 处理后有空格的string
*/
- (NSString *)insertSpacesEveryFourDigitsIntoString:(NSString *)string andPreserveCursorPosition:(NSUInteger *)cursorPosition{
NSMutableString *stringWithAddedSpaces = [NSMutableString new];
NSUInteger cursorPositionInSpacelessString = *cursorPosition;
for (NSUInteger i=0; i<string.length; i++) {
if(i>0)
{
if(i%4 == 0) {
[stringWithAddedSpaces appendString:@" "];
if(i<cursorPositionInSpacelessString) {
(*cursorPosition)++;
}
}
}
unichar characterToAdd = [string characterAtIndex:i];
NSString *stringToAdd = [NSString stringWithCharacters:&characterToAdd length:1];
[stringWithAddedSpaces appendString:stringToAdd];
}
return stringWithAddedSpaces;
}
#pragma 手机号码格式
- (NSString *)insertSpacesIntoPhoneNumberString:(NSString *)string andPreserveCursorPosition:(NSUInteger *)cursorPosition{
NSMutableString *stringWithAddedSpaces = [NSMutableString new];
NSUInteger cursorPositionInSpacelessString = *cursorPosition;
for (NSUInteger i=0; i<string.length; i++) {
if(i>0)
{
if(i == 3 || i == 7) {
[stringWithAddedSpaces appendString:@" "];
if(i<cursorPositionInSpacelessString) {
(*cursorPosition)++;
}
}
}
unichar characterToAdd = [string characterAtIndex:i];
NSString *stringToAdd = [NSString stringWithCharacters:&characterToAdd length:1];
[stringWithAddedSpaces appendString:stringToAdd];
}
return stringWithAddedSpaces;
}
#pragma 身份证格式
- (NSString *)insertSpacesIntoIDNOString:(NSString *)string andPreserveCursorPosition:(NSUInteger *)cursorPosition{
NSMutableString *stringWithAddedSpaces = [NSMutableString new];
NSUInteger cursorPositionInSpacelessString = *cursorPosition;
for (NSUInteger i=0; i<string.length; i++) {
if(i>0)
{
if(i == 6 || i == 10 || i == 14) {
[stringWithAddedSpaces appendString:@" "];
if(i<cursorPositionInSpacelessString) {
(*cursorPosition)++;
}
}
}
unichar characterToAdd = [string characterAtIndex:i];
NSString *stringToAdd = [NSString stringWithCharacters:&characterToAdd length:1];
[stringWithAddedSpaces appendString:stringToAdd];
}
return stringWithAddedSpaces;
}
@end
这里需要注意的是OC的分类允许给分类添加属性,但不会自动生成getter、setter方法,所以我们必须自己实现他的 getter、setter,但是要通过运行时建立关联引用! 我们这个类实现也正是利用OC的这个特征,在重写 setter方法的时机给UITextField文本格式的实现提供了入口!