需求
限制字符输入长度是个常见的需求,比如注册的账号或者密码。通常,从用户体验的角度,iOS App中当输入超过制定长度的字符时不需要显式的弹出提示,而只需要让超过的字符不显示即可。这个功能看似简单,但是考虑到一些输入系统例如中文输入法的联想功能,就不那么简单。
一般的实现
以UITextField为例,通常的做法是在delegate中做文章。这样的解决方案很多,stackflow上一个比较全面的解答:Set the maximum character length of a UITextField,大致的思路就是在输入即将要替换的时候,计算最终要显示的字符串。这个方法对于英文输入是没有问题的,但是对于其他语言如中文输入就会存在问题。举例来说中文拼音输入“的”时,用户需要输入de,在未选中“的”时,de以选中的状态在输入框中显示,并作为输入框的内容,如下图:
按照中文的输入法,de两个字符并不是最终显示在UITextField控件中,所以背景有选中区域,但此时UITextFiled的属性text的内容包含de。然后,右图显示的是输入“的”后产生的联想,注意此时点击“确”的时候,UITextField的任一delegate都不会响应。所以,要另想办法解决。
解决办法
UITextField有一个属性markedTextRange用于标识如中文拼音输入字母时的情形,那么解决的思路:
- UITextFiled的delegate中先检查markedTextRange是否为空,不为空时不做检查允许输入;否则按原先的思路计算字符长度
- 注册UITextFieldTextDidChangeNotification消息,用于处理联想输入情形
下面给出代码:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//delete
if ([string length] == 0 || textField.markedTextRange != nil)
{
return YES;
}
if (([string length] + [textField.text length] > MAX_LEN ) )
{
return NO;
}
return YES;
}
- (void)textChange:(NSNotification *)noti
{
if (self.waterTextField.markedTextRange != nil)
{
return;
}
NSString *string = self.waterTextField.text;
if ([string length] > MAX_LEN)
{
self.waterTextField.text = [string substringToIndex:MAX_LEN];
}
}
需要注意的是在UITextFieldTextDidChangeNotification的响应中需要检测markedTextRange,只有在为nil的情况下再进行字符截断处理,否则程序会抛出异常。
Comments