在 iOS 开发中,常见场景有 获取用户输入同时显示当前输入的字数。并限制输入内容的总长度,字数在临界时 裁剪用户输入。
简单以 textfield 对象中 text 属性的 length 属性(即 textField.text.length)作为长度时,会有以下明显缺点:
a、当前输入为中文输入,即[[UITextInputMode currentInputMode] primaryLanguage]字符串为@"zh-Hans"时,且输入法为系统自带的九宫格或全键盘时;当点击数个拼音按键,但并未选定候选词时,当前的显示的字数里就包含了候选的高亮显示的拼音字符数,造成字数显示不准。
b、当前为中文输入,且为系统输入法时。若此时的需求中,包括用户输入的字数的限制时;普通的做法是 实时判断textField.text.length,在长度超过某个值时,对输入字符串进行裁剪,即:textField.text = [ textField.text substringToIndex : XXX] ; 此时如果当前有高亮的拼音存在,执行字符串裁剪后会出现程序崩溃( 隐约记得某几个ios系统不会出现崩溃 )。崩溃原因是 当前高亮显示的拼音部分并不是可以改动的textField.text的值,尝试改动这部分数据就会造成崩溃。想想,高亮的拼音即不可以改,又增加了长度数,想不想呵呵。。
下面讲下目前测试的,较正确的方式:
1、首先监听object参数对应的textfield控件的键盘动作:
[[NSNotificationCenter defaultCenter]addObserver:self
selector:@selector(textFieldEditChanged:)
name:@"UITextFieldTextDidChangeNotification"
object:self.textFieldText];
2、定义好 textFieldEditChanged: 回调函数的动作:
- (void)textFieldEditChanged:(NSNotification *)info{
UITextField *textField = (UITextField *)info.object;
UITextRange *range = textField.markedTextRange; //取出marked高亮区
if(range) //表示有高亮
{
UITextPosition *end = range.end;
UITextPosition *pos = range.start;
NSInteger markedLength = 0; //记录高亮区间长度
while (markedLength < 1000) {
/*这里的1000表示正常输入不能达到的数,若出现极端情况,输入超过1000则只是字数
显示不准而已,不会出现其他危险*/
//后移偏移值pos 直至为end
pos = [self.textFieldText positionFromPosition:pos offset:1];
if([pos isEqual:end])
break;
//记录marked区长度
++markedLength;
}
NSInteger markLen = markedLength +1; //表示高亮区域长度
self.markedLength.text = [NSString stringWithFormat:@"%ld",len]; //显示高亮区长度
NSInteger unmarkedLen = textField.text.length - markLen;
//控件字符串长度,减高亮区长度,为用户已经完成输入的字符串长度。
self.textLength.text = [NSString stringWithFormat:@"%ld",unmarkedLen ];
}
else //表示当前没有高亮
{
self.markedLength.text = @"0";
self.textLength.text = [NSString stringWithFormat:@"%ld",textField.text.length];
}
}
补充:获取高亮区的字符串长度并没有必要,只要在有高亮时不更新字符数,也是正常的逻辑。
超出限定长度,并对字符串进行裁剪 的代码,自己好好考虑并添加吧。
补充: 看了 小失同学 的这篇文章之后,发觉 在当前输入法为表情时,且由于表情占2个字符而不是普通文字的1个字符宽度,因此会造成裁剪表情,造成系统无法解析当前字符串而崩溃。
ps:除了小失同学讲的这种情况,亲测 在第三方输入法时输入emoji表情时,当前语言输入依旧可能是@"zh-Hans",即汉字输入模式。 考虑到无论自带键盘输入,还是三方表情输入时,都是不存在前文所讲的高亮字符串。则可将这两种情况分别加 在无高亮的语句块中。
如下代码else块表示不存在marked高亮时。