搗鼓了半天 終于把自己的博客搭建好了,發(fā)一篇文章試試手。公司里的服務(wù)器比較low,不能支持emoji表情,本意是解決這個問題,自定義一個UITextField的控件。后來索性把長度校驗也做了進去,基本滿足了正常的需求。
一 限制文本長度
目前textfield的輸入大概就2種:
通過點擊鍵盤按鍵輸入的
通過點擊鍵盤聯(lián)想輸入的 [同時有高亮字符(maskText)占位]
首先參考了一些文章:
主要我看這篇文章比較全
http://www.lxweimin.com/p/2d1c06f2dfa4
網(wǎng)上能搜索到的主要在這篇文章里都有體現(xiàn)了,但是也是有問題的。
先說說實現(xiàn)的方法
對應(yīng)上述3種情況限制長度的主要方法
點擊鍵盤輸入的不管中英文點擊鍵盤就能喚起UITextFieldDelegate
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
所以通過這個方法可以達到過濾掉鍵盤輸入的文字超長的效果。
- 中文輸入等 都是通過點擊鍵盤后選取鍵盤聯(lián)想也就是上述第二種情況,在上面的代理中無法監(jiān)聽,不過UITextField身為UIControl 可以通過
[self addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>]
通過監(jiān)聽UIControlEventEditingChanged 來實現(xiàn)效果
==注意:在需要高亮字符占位的輸入法(不僅只有中文輸入法),在點擊鍵盤按鍵輸入時(拼音,筆畫等)還是能被第一種情況的代理監(jiān)聽,只有當選取聯(lián)想出來的文字的時候才不能。==
反例分析
現(xiàn)在網(wǎng)上搜索一大堆限制文字長度的方法大概是這樣(我就用上述連接上的代碼了反正都類似)
-(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];
// 沒有高亮選擇的字,則對已輸入的文字進行字數(shù)統(tǒng)計和限制
if (!position) {
if (toBeString.length > kMaxLength) {
textField.text = [toBeString substringToIndex:kMaxLength];
}
} // 有高亮選擇的字符串,則暫不對文字進行統(tǒng)計和限制
else{
}
} // 中文輸入法以外的直接對其統(tǒng)計限制即可,不考慮其他語種情況 else{
if (toBeString.length > kMaxLength) {
textField.text = [toBeString substringToIndex:kMaxLength];
}
}}
首先看代碼就覺得這個是用通知的形勢來發(fā)送UIControlEventEditingChanged的事件,這明顯不可取,同一個頁面可能有多個textField這玩意還要做個校驗通知是誰發(fā)出來的。
然后他寫死限制了中文輸入法,這不是很可取,日語,韓語輸入法的形式和中文差不多,還有特意過濾的高亮狀態(tài),對高亮狀態(tài)的字不進行字數(shù)統(tǒng)計,這明顯是錯的。高亮狀態(tài)的時候,可以不停的輸入在還沒有結(jié)束輸入之前完全可能超過字數(shù)限制,這時候直接取textField.text的長度就超過了要求。
解決方案
針對多個控件發(fā)通知的問題,使用
[self addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>]
通過監(jiān)聽UIControlEventEditingChanged 明顯更加合理。沒必要特別排除高亮狀態(tài),高亮狀態(tài)仍然應(yīng)該屬于校驗范圍內(nèi)。
還有一點比較隱蔽,就是這時候就算字數(shù)超過被截去,用戶仍然可以不停的按鍵盤,這時候,自動聯(lián)想還能繼續(xù),導(dǎo)致自動聯(lián)想出來的字數(shù)越來越多,交互很不合理,用戶體驗不佳。這時候要同時實現(xiàn)
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
限制用戶點擊的鍵盤輸入。這里可能有人會說 ==這樣在輸入全部是英文的情況下是可以的. 但是當輸入是中文時, 由于shouldChangeCharactersInRange判斷的是當前鍵盤的字符數(shù), 會出現(xiàn)這樣的問題: 比如你還剩下2個字可以打, 你想輸入"張三", "張"的拼音是Zhang, 于是你在輸入Zh的時候就無法輸入了. 顯然, 這樣的結(jié)果不是我們想要的.== 我再強調(diào)下但是這必須要這樣。因為如果你不限制高亮字符讓其出現(xiàn)在文本框內(nèi),使用控件的同學(xué)直接取textField.text這時候的文本自然包含高亮文本,導(dǎo)致長度就超過了要求(如 要求是5個字不進行限制,輸入xxx后再輸入張三的拼音得到 xxx==zhangsan==這時候張三還在高亮狀態(tài),然后用戶直接點擊保存,這時候如果使用控件的人不先進行 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表情
還是網(wǎng)上一搜索 搜到的都不合理只好自己搗鼓。直接上反例。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//檢查 string string 包含emoji表情則return NO;
}
上訴代碼解決不了通過文字聯(lián)想出來的emoji表情輸入,因為這個方法更本監(jiān)聽不到。
其次上述代碼非常隱晦的屏蔽了九宮格輸入法。因為點擊九宮格按鍵得到的string就是emoji表情符號文字 ①②③④⑤⑥⑦⑧⑨⑩
解決方案
想到用UIControlEventEditingChanged事件,但是不可取,因為這個事件并不知道emoji表情添加到哪個位置上,如果每次在此方法中做個遍歷,去掉emoji太耗性能。所以采用
- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
這個方法,通過聯(lián)想得到的emoji表情,選取后必然調(diào)用這個,我們只要重寫此方法,就能做到過濾。在
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
方法中加入校驗,當前是emoji表情鍵盤的時候才進行驗證,==此處有坑,網(wǎng)上找的方法全都是采用if ([[[UITextInputMode currentInputMode ]primaryLanguage] isEqualToString:@"emoji"])
currentInputMode 這明明都是IOS7就廢棄的方法,好吧那就采用 textField.textInputMode.primaryLanguage 結(jié)果選擇emoji表情的時候得到的是nil 直接判斷nil為moeji表情鍵盤太不合理了==,網(wǎng)上找了半天沒找到,然后自己瞎搗鼓了下發(fā)現(xiàn)了[UITextInputMode activeInputModes]
這里有然后就寫了個方法 不過得到的數(shù)組實際都是iOS的私有類,不過根據(jù)泛型參數(shù)估且認為他是NSString *類型然后通過KVC可以取得我們想要的結(jié)果。
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;
}
==寫到這里,具體控件實現(xiàn),設(shè)計思路放下一篇博客里講==