下面所示方法,TextField是禁用了复制、粘贴、剪切等操作的
如果需要保留复制、粘贴、剪切等操作且保证字符串每隔3位添加空格显示,请看
iOS UITextField 长串数字每隔3位添加空格显示(二)
整体思路
-
1. 先只考虑无空格时光标的变化。比如 输入字符时,光标位置+1,删除时,光标位置-1
-
2.计算光标位置前的空格数,进而获取到带空格的光标位置。此光标位置即光标的最终位置。光标最终位置 = 无空格光标前空格数 + 无空格变化后的光标位置
-
3.原始字符串添加空格
示例:
比如 当前文本为123☐|45, 其中 | 表示光标,☐表示空格,即 123后有个空格,光标在空格后。此时用户输入数字6。
1.获取不带空格的光标位置,即 当前光标位置-当前光标位置前的空格数,当前光标位置为4,当前光标位置前的空格数为1,即不带空格的光标位置为3
123|45
2.获取变化后的不带空格光标位置,即不带空格的光标位置+1,为4
1236|45
3.计算变化后的带空格光标位置,即变化后不带空格光标位置+变化后不带空格光标位置前的需要显示的空格数。1236 需要显示一个空格,则变化后的光标位置为5
4.原始字符串添加空格
即 123☐645
变化后的光标位置为5,即123☐6|45
上代码
// 核心代码
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// 限制表情输入
if ([string emo_containsEmoji]) {
return NO;
}
// 限制非数字 和 字符串长度限制
NSString * toBeString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSUInteger wordCountlimit = 19;
NSString *wordLimitString = kNumbers;
if (toBeString.length > wordCountlimit) {
return NO;
}
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:wordLimitString] invertedSet];
NSString * filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
BOOL basicTest = [string isEqualToString:filtered];
if(!basicTest) {
return NO;
}
// 设置textfiled text 和 光标位置
if (string.length > 0) {
[self handleTextFieldAddEvent:string];
}else{
[self handleTextFieldDeleteEvent];
}
[self checkJoinBtnStatus];
return NO;
}
- (void)handleTextFieldAddEvent:(NSString *)numStr {
// 思路
/*
1. 计算不带‘ ’的字符串的光标 A
2. 计算不带‘ ’的字符串 变化后的光标B B = A +1
3. 计算带‘ ’的字符串 变化后的光标C 光标C是通过截取到光标B的字符串中含有‘ ’的个数来计算的
*/
NSString *placeholder = @" ";
// 变化前
// 1.获取当前光标信息
NSRange currentTextRange = [self.meetingNumTextFiled selectedRange];
NSInteger rangeLength = currentTextRange.length;
//当前带空格的Text
NSString *currentTextString = self.meetingNumTextFiled.text;
// 2.获取不带占位符的光标
NSString *subCursorCurrentString = [self.meetingNumTextFiled.text substringToIndex:currentTextRange.location];
NSInteger spaceCount = [[subCursorCurrentString mutableCopy] replaceOccurrencesOfString:placeholder withString:@"" options:NSLiteralSearch range:NSMakeRange(0, subCursorCurrentString.length)];
NSRange noSpaceCurrentRange = NSMakeRange(currentTextRange.location-spaceCount, rangeLength);
// 3.当前 不带占位符的Text
NSString *noSpaceCurrentTextString = [currentTextString stringByReplacingOccurrencesOfString:placeholder withString:@""];
// 变化后
// 1.变化后 不带占位符的Text的range
NSRange noSpaceChangedRange = NSMakeRange(noSpaceCurrentRange.location+numStr.length, rangeLength);
// 2.变化后 不带空格的Text
NSMutableString *tempStringm = [[NSMutableString alloc] initWithString:noSpaceCurrentTextString];
[tempStringm insertString:numStr atIndex:noSpaceCurrentRange.location];
NSString *noSpaceChangedTextString = [tempStringm mutableCopy];
// 3.变化后 带占位符的Text 的range
NSString * noSpaceSubCursorChangedString = [noSpaceChangedTextString substringToIndex:noSpaceChangedRange.location];
// 计算光标前占位符个数
long subCursorChangedSpaceCount = 0;
if (noSpaceSubCursorChangedString.length >= 1) {
subCursorChangedSpaceCount = (noSpaceSubCursorChangedString.length -1) / 3;
}
NSRange changedTextRange = NSMakeRange(noSpaceChangedRange.location+subCursorChangedSpaceCount, rangeLength);
// 4.变化后 带占位符的Text
NSMutableString *muStr = [noSpaceChangedTextString mutableCopy];
if (muStr.length >3) {
int i=2;
while (i<muStr.length) {
if ((i+1)%4==0) {
[muStr insertString:placeholder atIndex:i];
}
i++;
}
}
self.meetingNumTextFiled.text = muStr;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//必须加延迟,否则无法更新光标位置
[self.meetingNumTextFiled setSelectedRange:changedTextRange];
});
}
- (void)handleTextFieldDeleteEvent {
/*
1. 计算不带‘-’的字符串的光标 A
2. 计算不带‘-’的字符串 变化后的光标B B = A -1
3. 计算带‘-’的字符串 变化后的光标C 光标C是通过截取到光标B的字符串中含有‘-’的个数来计算的
*/
NSString *placeholder = @" ";
// 变化前
// 1.获取当前光标信息
NSRange currentTextRange = [self.meetingNumTextFiled selectedRange];
NSInteger rangeLength = currentTextRange.length;
//当前带空格的Text
NSString *currentTextString = self.meetingNumTextFiled.text;
// 2.获取不带占位符的光标
NSString *subCursorCurrentString = [self.meetingNumTextFiled.text substringToIndex:currentTextRange.location];
NSInteger spaceCount = [[subCursorCurrentString mutableCopy] replaceOccurrencesOfString:placeholder withString:@"" options:NSLiteralSearch range:NSMakeRange(0, subCursorCurrentString.length)];
NSRange noSpaceCurrentRange = NSMakeRange(currentTextRange.location-spaceCount, rangeLength);
// 3.当前 不带占位符的Text
NSString *noSpaceCurrentTextString = [currentTextString stringByReplacingOccurrencesOfString:placeholder withString:@""];
// 变化后
// 1.变化后 不带占位符的Text的range
if (noSpaceCurrentRange.location<1) {
return ;
}
NSRange noSpaceChangedRange = NSMakeRange(noSpaceCurrentRange.location-1, rangeLength);
// 2.变化后 不带空格的Text
NSMutableString *tempStringm = [[NSMutableString alloc] initWithString:noSpaceCurrentTextString];
NSInteger deleteLocation = (NSInteger)noSpaceChangedRange.location;
deleteLocation = (deleteLocation > 0 ? deleteLocation : 0);
if (tempStringm.length-1>=deleteLocation) {
[tempStringm deleteCharactersInRange:NSMakeRange(deleteLocation, 1)];
}
NSString *noSpaceChangedTextString = [tempStringm mutableCopy];
// 3.变化后 带占位符的Text 的range
NSString * noSpaceSubCursorChangedString = [noSpaceChangedTextString substringToIndex:noSpaceChangedRange.location];
// 计算光标前占位符个数
long subCursorChangedSpaceCount = 0;
if (noSpaceSubCursorChangedString.length >= 1) {
subCursorChangedSpaceCount = (noSpaceSubCursorChangedString.length -1) / 3;
}
NSRange changedTextRange = NSMakeRange(noSpaceChangedRange.location+subCursorChangedSpaceCount, rangeLength);
// 4.变化后 带占位符的Text
NSMutableString *muStr = [noSpaceChangedTextString mutableCopy];
if (muStr.length >3) {
int i=2;
while (i<muStr.length) {
if ((i+1)%4==0) {
[muStr insertString:placeholder atIndex:i];
}
i++;
}
}
self.meetingNumTextFiled.text = muStr;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//必须加延迟,否则无法更新光标位置
[self.meetingNumTextFiled setSelectedRange:changedTextRange];
});
}
// UITextField+ExtentRange
- (NSRange)selectedRange {
UITextPosition* beginning = self.beginningOfDocument;
UITextRange* selectedRange = self.selectedTextRange;
UITextPosition* selectionStart = selectedRange.start;
UITextPosition* selectionEnd = selectedRange.end;
const NSInteger location = [self offsetFromPosition:beginning toPosition:selectionStart];
const NSInteger length = [self offsetFromPosition:selectionStart toPosition:selectionEnd];
return NSMakeRange(location, length);
}
- (void)setSelectedRange:(NSRange)range {
UITextPosition* beginning = self.beginningOfDocument;
UITextPosition* startPosition = [self positionFromPosition:beginning offset:range.location];
UITextPosition* endPosition = [self positionFromPosition:beginning offset:range.location + range.length];
UITextRange* selectionRange = [self textRangeFromPosition:startPosition toPosition:endPosition];
[self setSelectedTextRange:selectionRange];
}
设置textfield的selectedTextRange需在设置textfield的text后,不然光标会一直在文本最后
目前不支持粘贴
可禁用UITextfield的复制粘贴功能