iOS - UITextField限制长度 emoji表情

捣鼓了半天 终于把自己的博客搭建好了,发一篇文章试试手。公司里的服务器比较low,不能支持emoji表情,本意是解决这个问题,自定义一个UITextField的控件。后来索性把长度校验也做了进去,基本满足了正常的需求。

我的博客 http://www.linit.space

一 限制文本长度


  • 目前textfield的输入大概就2种:

  • 通过点击键盘按键输入的

  • 通过点击键盘联想输入的 [同时有高亮字符(maskText)占位]

首先参考了一些文章:

主要我看这篇文章比较全

http://www.jianshu.com/p/2d1c06f2dfa4

网上能搜索到的主要在这篇文章里都有体现了,但是也是有问题的。

先说说实现的方法
  • 对应上述3种情况限制长度的主要方法

  • 点击键盘输入的不管中英文点击键盘就能唤起UITextFieldDelegate

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string所以通过这个方法可以达到过滤掉键盘输入的文字超长的效果。

  • 中文输入等 都是通过点击键盘后选取键盘联想也就是上述第二种情况,在上面的代理中无法监听,不过UITextField身为UIControl 可以通过[self addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>] 通过监听UIControlEventEditingChanged 来实现效果

==注意:在需要高亮字符占位的输入法(不仅只有中文输入法),在点击键盘按键输入时(拼音,笔画等)还是能被第一种情况的代理监听,只有当选取联想出来的文字的时候才不能。==

反例分析

现在网上搜索一大堆限制文字长度的方法大概是这样(我就用上述连接上的代码了反正都类似)


-(void)textFiledEditChanged:(NSNotification *)obj{

UITextField *textField = (UITextField *)obj.object;

NSString *toBeString = textField.text;

NSString *lang = [[UITextInputMode currentInputMode] primaryLanguage]; // 键盘输入模式

if ([lang isEqualToString:@"zh-Hans"]) { // 简体中文输入,包括简体拼音,健体五笔,简体手写

UITextRange *selectedRange = [textField markedTextRange];      //获取高亮部分

UITextPosition *position = [textFieldpositionFromPosition:selectedRange.start offset:0];

// 没有高亮选择的字,则对已输入的文字进行字数统计和限制

if (!position) {

if (toBeString.length > kMaxLength) {

textField.text = [toBeString substringToIndex:kMaxLength];

}

}      // 有高亮选择的字符串,则暂不对文字进行统计和限制

else{

}

}  // 中文输入法以外的直接对其统计限制即可,不考虑其他语种情况  else{

if (toBeString.length > kMaxLength) {

textField.text = [toBeString substringToIndex:kMaxLength];

}

}}

  • 首先看代码就觉得这个是用通知的形势来发送UIControlEventEditingChanged的事件,这明显不可取,同一个页面可能有多个textField这玩意还要做个校验通知是谁发出来的。

  • 然后他写死限制了中文输入法,这不是很可取,日语,韩语输入法的形式和中文差不多,还有特意过滤的高亮状态,对高亮状态的字不进行字数统计,这明显是错的。高亮状态的时候,可以不停的输入在还没有结束输入之前完全可能超过字数限制,这时候直接取textField.text的长度就超过了要求。

解决方案
  1. 针对多个控件发通知的问题,使用[self addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>] 通过监听UIControlEventEditingChanged 明显更加合理。

  2. 没必要特别排除高亮状态,高亮状态仍然应该属于校验范围内。

  3. 还有一点比较隐蔽,就是这时候就算字数超过被截去,用户仍然可以不停的按键盘,这时候,自动联想还能继续,导致自动联想出来的字数越来越多,交互很不合理,用户体验不佳。这时候要同时实现- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string限制用户点击的键盘输入。这里可能有人会说 ==这样在输入全部是英文的情况下是可以的. 但是当输入是中文时, 由于shouldChangeCharactersInRange判断的是当前键盘的字符数, 会出现这样的问题: 比如你还剩下2个字可以打, 你想输入"张三", "张"的拼音是Zhang, 于是你在输入Zh的时候就无法输入了. 显然, 这样的结果不是我们想要的.== 我再强调下但是这必须要这样。因为如果你不限制高亮字符让其出现在文本框内,使用控件的同学直接取textField.text这时候的文本自然包含高亮文本,导致长度就超过了要求(如 要求是5个字不进行限制,输入xxx后再输入张三的拼音得到 xxx==zhangsan==这时候张三还在高亮状态,然后用户直接点击保存,这时候如果使用控件的人不先进行 endEditing操作,然后直接取textField.text 取得的文本肯定是 xxxzhangsan 超过了5个字的要求,控件限制文本长度的功能不能依赖与控件使用者,所以不可取)

Demo

//self.helpObject 就是一个 UITextField

//[self addTarget:self.helper action:@selector(textFiledEditChanged) forControlEvents:UIControlEventEditingChanged];

- (void)textFiledEditChanged

{

if (self.helpObject.maxLength != 0) {

NSInteger kmaxLength = self.helpObject.maxLength;

NSString *toBeString = self.helpObject.text;

//截取长度

if (toBeString.length > kmaxLength) {

self.helpObject.text = [toBeString substringToIndex:kmaxLength];

}

}

}

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

{

//长度校验 string.length > 0 排除删除按

if (self.helpObject.maxLength != 0 && string.length != 0) {

NSString *toBeString = [textField.text stringByReplacingCharactersInRange:range withString:string];

NSInteger kmaxLength = self.helpObject.maxLength;

if (toBeString.length > kmaxLength){

return NO;

}

}

return YES;

}

二 限制emoji表情


还是网上一搜索 搜到的都不合理只好自己捣鼓。直接上反例。


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

{

//检查 string  string 包含emoji表情则return NO;

}

  • 上诉代码解决不了通过文字联想出来的emoji表情输入,因为这个方法更本监听不到。

  • 其次上述代码非常隐晦的屏蔽了九宫格输入法。因为点击九宫格按键得到的string就是emoji表情符号文字 ①②③④⑤⑥⑦⑧⑨⑩

解决方案
  1. 想到用UIControlEventEditingChanged事件,但是不可取,因为这个事件并不知道emoji表情添加到哪个位置上,如果每次在此方法中做个遍历,去掉emoji太耗性能。所以采用- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange这个方法,通过联想得到的emoji表情,选取后必然调用这个,我们只要重写此方法,就能做到过滤。

  2. - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string方法中加入校验,当前是emoji表情键盘的时候才进行验证,==此处有坑,网上找的方法全都是采用if ([[[UITextInputMode currentInputMode ]primaryLanguage] isEqualToString:@"emoji"]) currentInputMode 这明明都是IOS7就废弃的方法,好吧那就采用 textField.textInputMode.primaryLanguage 结果选择emoji表情的时候得到的是nil 直接判断nil为moeji表情键盘太不合理了==,网上找了半天没找到,然后自己瞎捣鼓了下发现了[UITextInputMode activeInputModes]这里有然后就写了个方法 不过得到的数组实际都是iOS的私有类,不过根据泛型参数估且认为他是NSString *类型然后通过KVC可以取得我们想要的结果。

Demo

- (BOOL)nowIsEmojiKeyBorad

{

for (NSString *keyboardInputMode in [UITextInputMode activeInputModes]) {

if ([[keyboardInputMode valueForKey:PrimaryLanguage] isEqualToString:EmojiprimaryLanguage]) {
//这里ios7会崩溃的建议增加判断 本文不做展开 具体参见博客
NSNumber *isDisplayed = [keyboardInputMode valueForKey:IsDisplayed];

if ([isDisplayed boolValue] == YES) {

return YES;

}

}

}

return false;

}

- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange

{

//将含有emoji表情的文字替换为@""

NSString *helpMarkedText = [self.helper setMarkedText:markedText selectedRange:selectedRange];

[super setMarkedText:helpMarkedText selectedRange:selectedRange];

}

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

{

//判断是否是 emoji键盘 并且 string.length > 0 (排除删除按)

//检查 string  string 包含emoji表情则return NO;

}

==写到这里,具体控件实现,设计思路放下一篇博客里讲==

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容