搗鼓了半天 終于把自己的博客搭建好了拯辙,發(fā)一篇文章試試手丰涉。公司里的服務(wù)器比較low,不能支持emoji表情涎永,本意是解決這個(gè)問(wèn)題思币,自定義一個(gè)UITextField的控件。后來(lái)索性把長(zhǎng)度校驗(yàn)也做了進(jìn)去羡微,基本滿足了正常的需求谷饿。
一 限制文本長(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ò)了要求。
解決方案
針對(duì)多個(gè)控件發(fā)通知的問(wèn)題撕瞧,使用
[self addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>]
通過(guò)監(jiān)聽(tīng)UIControlEventEditingChanged 明顯更加合理陵叽。沒(méi)必要特別排除高亮狀態(tài)狞尔,高亮狀態(tài)仍然應(yīng)該屬于校驗(yàn)范圍內(nèi)。
還有一點(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)文字 ①②③④⑤⑥⑦⑧⑨⑩
解決方案
想到用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ò)濾量瓜。在
- (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ì)思路放下一篇博客里講==