TextField 输入身份证号手机号银行卡号格式化解决方案

问题描述

TextField中输入身份证号,手机号,银行卡号时每隔几位需要添加空格。当输入错误时需要从末尾或者中间删除,删除之后还要保持当前textfield的中内容保持每隔几位就有一个空格的格式。这篇文章主要是为了解决这个问题

==解决上面的问题主要要解决两个点:==

  • 光标的位置
  • 空格的位置

上面的两种情况又可以分为:

  • 从最后一位删除
  • 从中间删除
  • 一次删除一个和多个
  • 从最后一位添加
  • 从中间添加
  • 一次添加一位和多位

这几种情况都要考虑光标的位置和空格的位置,每次添加和删除都要重新计算.

实现:

首先详细说下👇的这个代理方法:

1
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
range

shouldChangeCharactersInRange :有location 和length 两个参数
location 是即将被替代的内容的位置
length 是即将被替代的内容的长度

string

用来替代在range位置内容的字符串

  • 假如:textfield中有内容为1234

三种情况解释下string 和range参数 :

  1. 光标在最后一位时删除一位 :那么string就是为空 range的location 就是光标前面的内容的下标即为3 length就是1 表示被删除的内容长度为1 ,结果是string占据了range表示的位置 即123,3后面的4被空字符串占据了即被删除了
  2. 光标在最后一位删除两位:操作,长按textfield选中23,点击删除。可以发现string依旧为空 ,range变为 location=1, length=2 即位置在下标为1 长度为2的字符串被空字符串替代了,还剩1,所谓的23被删除了
  3. 添加一个:光标在最后一位。输入一个2,此时range:location为1,length为0 即被替代的内容位置在下标为1的地方,长度是空。string为2,那么结果就是一个下标为1,长度为0的字符串被string替代了,即textfield内容添加了一个2,复制到textfield中的内容range 和 string 也是同样的适用

说的这么详细主要为下一步做准备。

UITextInput协议 中的几个属性和方法

设置光标的位置需要下面的两个方法

1
2
3
4
5

// 获取以fromPosition为基准偏移offset的光标位置。
- (nullable UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset;
// 创建一个UITextRange
- (nullable UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition;
  • 设置光标位置的方法

根据UITextInput协议的两个方法可以得出设置光标的位置的方法

1
2
3
4
5
6
7
+ (void)setCursorLocation:(UITextField *)textField withOffset:(NSInteger) offset{
// offset 光标要所处的位置
// 生成新的postion
UITextPosition *newPostion = [textField positionFromPosition:textField.beginningOfDocument offset:offset] ;
//设置光标 从一个点到另外一个点如果两个点一样 那么光标就在这个点
textField.selectedTextRange = [textField textRangeFromPosition:newPostion toPosition:newPostion];
}

==注意==:在textField中,有一个属性称之为selectedTextRange,这个属性为UITextRange类型,包含[start,end)两个值,通过实验可以发现,在没有文字被选取时,start 和 end的值一样 代表当前光标的位置;当有区域被选择时,start和end分别是选择的头和尾的光标位置

可以看出 setCursorLocation 方法中很重要的一个参数是偏移量

  • 添加空格的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
// 在指定的位置添加空格
+(NSString*)insertString:(NSString*)string withBlankLocations:(NSArray<NSNumber *>*)locations {
if (!string) {
return nil;
}
NSMutableString* mutableString = [NSMutableString stringWithString:[string stringByReplacingOccurrencesOfString:@" " withString:@""]];
for (NSNumber *location in locations) {
if (mutableString.length > location.integerValue) {
[mutableString insertString:@" " atIndex:location.integerValue];
}
}
return mutableString;
}

上面这个方法是根据传入的空格的位置,遍历整个字符串,在指定的位置为字符串添加一个空格. 这个方法调用的时机就是 textField 中的 text 发生改变时调用,比如说删除或者增加字符串

++那么以下就根据不同的情况来计算偏移量设置光标 和 添加空格++

删除字符串

如何判断是点击了键盘的删除

如上面所说 在

1
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

这个代理方法中 当string为空时就是删除。range是一个位置表示string的位置 如果string为空时 range.length 表示删除的长度

  1. 删除一位
    如果 range.length == 1
    如果string 为空 且 range的location 为当前textField.text的长度减一 即location是textField.text的最后一个字符时 表示在最后一位删除

① 如果在最后一位删除一位不需要设置光标的位置和添加空格

② 如果不是最后一位删除一位则要判断删除的是不是空格。如果是空格则会连续删除两次

1
2
3
4
5
6
7
// 不是最后一位
NSInteger locationOffset = range.location;
if (range.location < text.length && [text characterAtIndex:range.location] == ' ' && [textField.selectedTextRange isEmpty]) {
[textField deleteBackward]; // 删除空格
locationOffset --;
}
[textField deleteBackward];// 删除空格前面的字符

上面的代码调用了两次[textField deleteBackward] 删除了两次

此时需要修改空格的位置和光标的位置,偏移量 offset 就是 range.location 的值 ,每删除一位 offset 就要减1

  1. 删除多位
    同删除一位的逻辑一样 string为空切 range.length > 1 就表示一次删除多位

① 是否是在最后一位开始删除,如果再最后一位开始删除那么仍然不需要设置光标的位置,但是需要设置空格的位置

② 如果不是最后一位开始删除,则需要计算光标的位置,偏移量仍然是当前 range.location

添加字符串

如何判断是添加?

如上面所说 在

1
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

这个代理方法中 当string不为空时就是添加。range是一个位置表示string的位置 如果string不为空时 range.length 表示添加的字符串的长度

如果所输入的字符串长度还没有超出限制则直接添加到 textField 中然后在预定的位置添加空格

1
2
3
4
// 添加到textField 中 这个方法是 UIKeyInput 协议中的方法
[textField insertText:string];
//textField中的字符串发生变化需要重新设置空格
textField.text = [self insertString:textField.text withBlankLocations:blankLocation];

此时要计算偏移量 ,在计算是光标的位置是 range.location + string.length ,但是如果在光标位置出正好有空格则offset需要 +1 如下

1
2
3
4
5
6
7
8
NSInteger offset = range.location + string.length;

for (NSNumber *location in blankLocation) {
if (range.location == location.integerValue) {
offset ++;
}
}
[self setCursorLocation:textField withOffset:offset];

通过以上几种情况就可以解决文章开头描述的问题了.

Demo 在这里
我是 Demo

如果解决了您的问题,请点赞支持下哈!

坚持原创,您的支持将鼓励我继续创作!