iOS对textField进行字符长度限制的办法

时间:2023-03-10 02:48:33
iOS对textField进行字符长度限制的办法

在项目开发过程中,遇到这么一个需求,编辑标签时,输入的最大长度需要限制为24个字节。

查阅了一些材料,并参考了之前项目的相关处理办法,今天在这里总结一下解决方案。

1.写一个截取字符串的方法,将超长的字符串截取成符合长度的字符串。如果内容超长,就干掉最后一个字,再判断是否超过限制长度,如此循环,直到满足长度限制要求。这里注意一下,直接使用length方法,返回的字符数,而不是字节数,lengthOfBytesUsingEncoding可返回指定字符编码的字节数。

这里遇到了一个特殊的问题:当字符串最后一个字符是emoji表情符号时,如果长度超限,会发现截取后的字符串最后有乱码。究其原因,一般的汉字和英文字符,都只占一个lengh单位,例如“我是Tom”的lengh就是5。但是表情符号可能占多个length单位,比如2个或者3个,甚至更多。所以,只把最后一个length单位截取掉,其实是没有把该表情符号完全删除掉的。幸运的是,我们仍然可以使用lengthOfBytesUsingEncoding来解决此问题,当一个utf8字符的编码不完整时,我们发现lengthOfBytesUsingEncoding返回0,把这种情况也处理一下即可。

/**
* 截取字符串,使字符串满足最大长度要求
*
* @param sourceString 待截取的字符串
*
* @return 截取后的字符串
*/
-(NSString*)truncatedString:(NSString*)sourceString
{
NSString *temp = [NSString stringWithString:sourceString];
while(YES)
{
NSInteger stringLen = [temp lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; if(stringLen == && temp.length != )
{
//当字符串的length不为零,stringLen为0时,代表字符串包含了不完整的UTF8编码的字符,取自身length-1的字符串
temp = [temp substringToIndex:temp.length-];
continue;
} if (stringLen <= kMaxByteOfAlarmName) {
//字符串符合长度要求
break;
}
else
{
//字符串过长,取自身length-1的字符串
temp = [temp substringToIndex:temp.length-];
}
}
return temp;
}

2.添加对UITextField的编辑变化事件的监听:

[self.textField addTarget:self action:@selector(textLengthChange:) forControlEvents:UIControlEventEditingChanged];

3.实现对应的action:

-(void)textLengthChange:(id)sender

{

UITextField * textField=(UITextField*)sender;

if (textField.markedTextRange == nil)

{

NSString *truncatedString = [self truncatedString:textField.text];

if(![textField.text isEqualToString:truncatedString])

{

textField.text = truncatedString;

}

}

}

说明:

另外,中文输入时,和平时英文输入会不太一样,中文输入会出现正在输入拼音,还没有选汉字,拼音已经上去了:

iOS对textField进行字符长度限制的办法

这时,拼音本身占的字节可能大于选字后的汉字所占的字节,例如输入zhong,占5个字节,而如果用户选择“中”,只占三个字节。如果不专门考虑这种情况,就会出现明明还可以再输一个中文汉字,但是输入拼音的时候没法完成zhong的拼音输入。所以需要判断当时textField是否有已选中的内容。至于为什么要先判断是否截取前后相等,是因为如果截取了,光标会自动跑到最后去,所以当用户输入没有超长时,我们最好不要改变光标的位置。

4.针对步骤3中的图,如果在出现图中的状态下直接保存,那么textfiled会把未转换为汉字的拼音也一起保存进去。所以还需要在使用textfield的内容前再进行一下处理,把超出的部分删除,再执行一遍截取:

self.textField.text = [self truncatedString:self.textField.text];

Done。如果有什么问题,欢迎留言指出,一起讨论。

补充点东西:

为什么不用UITextField的代理方法shouldChangeCharactersInRange?

目前看来,此方法无法捕捉粘贴、拼音转汉字和联想(例如使用拼音输“中国”后,直接再键盘的候选词中可以选“万岁”)输入导致的变化。所以不采用。

更新:

2016.7.25:将相同的代码提取成方法,增加对表情等特殊字符的处理。另外,考虑一种场景,即输入时,光标不在末尾的情况,那么随着用户的输入,最后的字符将会删除。体验更好的情况应该是删除新输入的字符串的末尾。但由于我们无法获取到新输入的字符串(shouldChangeCharactersInRange 有局限性),可以考虑直接撤销本次更改,保留上次的内容(这要求每次输入完成后,需要将现有的内容保存起来)。鉴于这种场景很少见,且当前处理也不会出现超限的问题,暂时不处理。