iOS - UITextField限制長(zhǎng)度 emoji表情

搗鼓了半天 終于把自己的博客搭建好了拯辙,發(fā)一篇文章試試手丰涉。公司里的服務(wù)器比較low,不能支持emoji表情涎永,本意是解決這個(gè)問(wèn)題思币,自定義一個(gè)UITextField的控件。后來(lái)索性把長(zhǎng)度校驗(yàn)也做了進(jìn)去羡微,基本滿足了正常的需求谷饿。

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

一 限制文本長(zhǎng)度


  • 目前textfield的輸入大概就2種:

  • 通過(guò)點(diǎn)擊鍵盤(pán)按鍵輸入的

  • 通過(guò)點(diǎn)擊鍵盤(pán)聯(lián)想輸入的 [同時(shí)有高亮字符(maskText)占位]

首先參考了一些文章:

主要我看這篇文章比較全

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

網(wǎng)上能搜索到的主要在這篇文章里都有體現(xiàn)了,但是也是有問(wèn)題的。

先說(shuō)說(shuō)實(shí)現(xiàn)的方法
  • 對(duì)應(yīng)上述3種情況限制長(zhǎng)度的主要方法

  • 點(diǎn)擊鍵盤(pán)輸入的不管中英文點(diǎn)擊鍵盤(pán)就能喚起UITextFieldDelegate

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string所以通過(guò)這個(gè)方法可以達(dá)到過(guò)濾掉鍵盤(pán)輸入的文字超長(zhǎng)的效果妈倔。

  • 中文輸入等 都是通過(guò)點(diǎn)擊鍵盤(pán)后選取鍵盤(pán)聯(lián)想也就是上述第二種情況博投,在上面的代理中無(wú)法監(jiān)聽(tīng),不過(guò)UITextField身為UIControl 可以通過(guò)[self addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>] 通過(guò)監(jiān)聽(tīng)UIControlEventEditingChanged 來(lái)實(shí)現(xiàn)效果

==注意:在需要高亮字符占位的輸入法(不僅只有中文輸入法)盯蝴,在點(diǎn)擊鍵盤(pán)按鍵輸入時(shí)(拼音毅哗,筆畫(huà)等)還是能被第一種情況的代理監(jiān)聽(tīng),只有當(dāng)選取聯(lián)想出來(lái)的文字的時(shí)候才不能捧挺。==

反例分析

現(xiàn)在網(wǎng)上搜索一大堆限制文字長(zhǎng)度的方法大概是這樣(我就用上述連接上的代碼了反正都類(lèi)似)


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

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

NSString *toBeString = textField.text;

NSString *lang = [[UITextInputMode currentInputMode] primaryLanguage]; // 鍵盤(pán)輸入模式

if ([lang isEqualToString:@"zh-Hans"]) { // 簡(jiǎn)體中文輸入虑绵,包括簡(jiǎn)體拼音,健體五筆闽烙,簡(jiǎn)體手寫(xiě)

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

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

// 沒(méi)有高亮選擇的字翅睛,則對(duì)已輸入的文字進(jìn)行字?jǐn)?shù)統(tǒng)計(jì)和限制

if (!position) {

if (toBeString.length > kMaxLength) {

textField.text = [toBeString substringToIndex:kMaxLength];

}

}      // 有高亮選擇的字符串,則暫不對(duì)文字進(jìn)行統(tǒng)計(jì)和限制

else{

}

}  // 中文輸入法以外的直接對(duì)其統(tǒng)計(jì)限制即可黑竞,不考慮其他語(yǔ)種情況  else{

if (toBeString.length > kMaxLength) {

textField.text = [toBeString substringToIndex:kMaxLength];

}

}}

  • 首先看代碼就覺(jué)得這個(gè)是用通知的形勢(shì)來(lái)發(fā)送UIControlEventEditingChanged的事件捕发,這明顯不可取,同一個(gè)頁(yè)面可能有多個(gè)textField這玩意還要做個(gè)校驗(yàn)通知是誰(shuí)發(fā)出來(lái)的很魂。

  • 然后他寫(xiě)死限制了中文輸入法扎酷,這不是很可取,日語(yǔ),韓語(yǔ)輸入法的形式和中文差不多,還有特意過(guò)濾的高亮狀態(tài)焕毫,對(duì)高亮狀態(tài)的字不進(jìn)行字?jǐn)?shù)統(tǒng)計(jì)惠桃,這明顯是錯(cuò)的。高亮狀態(tài)的時(shí)候惰爬,可以不停的輸入在還沒(méi)有結(jié)束輸入之前完全可能超過(guò)字?jǐn)?shù)限制喊暖,這時(shí)候直接取textField.text的長(zhǎng)度就超過(guò)了要求。

解決方案
  1. 針對(duì)多個(gè)控件發(fā)通知的問(wèn)題撕瞧,使用[self addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>] 通過(guò)監(jiān)聽(tīng)UIControlEventEditingChanged 明顯更加合理陵叽。

  2. 沒(méi)必要特別排除高亮狀態(tài)狞尔,高亮狀態(tài)仍然應(yīng)該屬于校驗(yàn)范圍內(nèi)。

  3. 還有一點(diǎn)比較隱蔽巩掺,就是這時(shí)候就算字?jǐn)?shù)超過(guò)被截去偏序,用戶(hù)仍然可以不停的按鍵盤(pán),這時(shí)候胖替,自動(dòng)聯(lián)想還能繼續(xù)研儒,導(dǎo)致自動(dòng)聯(lián)想出來(lái)的字?jǐn)?shù)越來(lái)越多,交互很不合理,用戶(hù)體驗(yàn)不佳独令。這時(shí)候要同時(shí)實(shí)現(xiàn)- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string限制用戶(hù)點(diǎn)擊的鍵盤(pán)輸入端朵。這里可能有人會(huì)說(shuō) ==這樣在輸入全部是英文的情況下是可以的. 但是當(dāng)輸入是中文時(shí), 由于shouldChangeCharactersInRange判斷的是當(dāng)前鍵盤(pán)的字符數(shù), 會(huì)出現(xiàn)這樣的問(wèn)題: 比如你還剩下2個(gè)字可以打, 你想輸入"張三", "張"的拼音是Zhang, 于是你在輸入Zh的時(shí)候就無(wú)法輸入了. 顯然, 這樣的結(jié)果不是我們想要的.== 我再?gòu)?qiáng)調(diào)下但是這必須要這樣。因?yàn)槿绻悴幌拗聘吡磷址屍涑霈F(xiàn)在文本框內(nèi)燃箭,使用控件的同學(xué)直接取textField.text這時(shí)候的文本自然包含高亮文本冲呢,導(dǎo)致長(zhǎng)度就超過(guò)了要求(如 要求是5個(gè)字不進(jìn)行限制,輸入xxx后再輸入張三的拼音得到 xxx==zhangsan==這時(shí)候張三還在高亮狀態(tài)招狸,然后用戶(hù)直接點(diǎn)擊保存敬拓,這時(shí)候如果使用控件的人不先進(jìn)行 endEditing操作,然后直接取textField.text 取得的文本肯定是 xxxzhangsan 超過(guò)了5個(gè)字的要求裙戏,控件限制文本長(zhǎng)度的功能不能依賴(lài)與控件使用者恩尾,所以不可取)

Demo

//self.helpObject 就是一個(gè) 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;

//截取長(zhǎng)度

if (toBeString.length > kmaxLength) {

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

}

}

}

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

{

//長(zhǎng)度校驗(yàn) 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表情


還是網(wǎng)上一搜索 搜到的都不合理只好自己搗鼓。直接上反例挽懦。


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

{

//檢查 string  string 包含emoji表情則return NO;

}

  • 上訴代碼解決不了通過(guò)文字聯(lián)想出來(lái)的emoji表情輸入翰意,因?yàn)檫@個(gè)方法更本監(jiān)聽(tīng)不到。

  • 其次上述代碼非常隱晦的屏蔽了九宮格輸入法信柿。因?yàn)辄c(diǎn)擊九宮格按鍵得到的string就是emoji表情符號(hào)文字 ①②③④⑤⑥⑦⑧⑨⑩

解決方案
  1. 想到用UIControlEventEditingChanged事件冀偶,但是不可取,因?yàn)檫@個(gè)事件并不知道emoji表情添加到哪個(gè)位置上渔嚷,如果每次在此方法中做個(gè)遍歷进鸠,去掉emoji太耗性能。所以采用- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange這個(gè)方法形病,通過(guò)聯(lián)想得到的emoji表情客年,選取后必然調(diào)用這個(gè),我們只要重寫(xiě)此方法漠吻,就能做到過(guò)濾量瓜。

  2. - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string方法中加入校驗(yàn),當(dāng)前是emoji表情鍵盤(pán)的時(shí)候才進(jìn)行驗(yàn)證途乃,==此處有坑绍傲,網(wǎng)上找的方法全都是采用if ([[[UITextInputMode currentInputMode ]primaryLanguage] isEqualToString:@"emoji"]) currentInputMode 這明明都是IOS7就廢棄的方法,好吧那就采用 textField.textInputMode.primaryLanguage 結(jié)果選擇emoji表情的時(shí)候得到的是nil 直接判斷nil為moeji表情鍵盤(pán)太不合理了==,網(wǎng)上找了半天沒(méi)找到烫饼,然后自己瞎搗鼓了下發(fā)現(xiàn)了[UITextInputMode activeInputModes]這里有然后就寫(xiě)了個(gè)方法 不過(guò)得到的數(shù)組實(shí)際都是iOS的私有類(lèi)猎塞,不過(guò)根據(jù)泛型參數(shù)估且認(rèn)為他是NSString *類(lèi)型然后通過(guò)KVC可以取得我們想要的結(jié)果。

Demo

- (BOOL)nowIsEmojiKeyBorad

{

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

if ([[keyboardInputMode valueForKey:PrimaryLanguage] isEqualToString:EmojiprimaryLanguage]) {
//這里ios7會(huì)崩潰的建議增加判斷 本文不做展開(kāi) 具體參見(jiàn)博客
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鍵盤(pán) 并且 string.length > 0 (排除刪除按)

//檢查 string  string 包含emoji表情則return NO;

}

==寫(xiě)到這里杠纵,具體控件實(shí)現(xiàn)荠耽,設(shè)計(jì)思路放下一篇博客里講==

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市比藻,隨后出現(xiàn)的幾起案子铝量,更是在濱河造成了極大的恐慌,老刑警劉巖韩容,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件款违,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡群凶,警方通過(guò)查閱死者的電腦和手機(jī)插爹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)请梢,“玉大人赠尾,你說(shuō)我怎么就攤上這事∫慊。” “怎么了气嫁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)够坐。 經(jīng)常有香客問(wèn)我寸宵,道長(zhǎng),這世上最難降的妖魔是什么元咙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任梯影,我火速辦了婚禮,結(jié)果婚禮上庶香,老公的妹妹穿的比我還像新娘甲棍。我一直安慰自己,他們只是感情好赶掖,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布感猛。 她就那樣靜靜地躺著,像睡著了一般奢赂。 火紅的嫁衣襯著肌膚如雪陪白。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天呈驶,我揣著相機(jī)與錄音拷泽,去河邊找鬼。 笑死袖瞻,一個(gè)胖子當(dāng)著我的面吹牛司致,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播聋迎,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼脂矫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了霉晕?” 一聲冷哼從身側(cè)響起庭再,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎牺堰,沒(méi)想到半個(gè)月后拄轻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伟葫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年恨搓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筏养。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斧抱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出渐溶,到底是詐尸還是另有隱情辉浦,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布茎辐,位于F島的核電站宪郊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拖陆。R本人自食惡果不足惜弛槐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慕蔚。 院中可真熱鬧丐黄,春花似錦、人聲如沸孔飒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坏瞄。三九已至桂对,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鸠匀,已是汗流浹背蕉斜。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宅此。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓机错,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親父腕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弱匪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容