1. 程式人生 > >如何更好地限制一個UITextField的輸入長度

如何更好地限制一個UITextField的輸入長度

要限制一個UITextField的輸入字數(參考連結),首先想到的應該是通過

UITextFieldDelegate

的代理方法來限制:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;   // return NO to not change text

比如要設定字數限制為20:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if
(textField == self.titleField) { if (textField.length > 20) return NO; } return YES; }

但是這樣的限制簡單粗暴,可能會影響使用者正常邏輯下的輸入,比如輸入了20個字元後,要退格回刪字元。
這時候我們可能會考慮“Detect backspace in UITextField”,比如簡單地判斷replacementString的長度是否為0
接著我們可能還會遇到使用者已經輸入20個字元了,這時候繼續輸入---不過是選擇了部分文字進行替換-----無法進行了,這也妨礙了使用者的正常操作,所以限制的程式碼版本可能會演進為:

#pragma mark - UITextFieldDelegate

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField == self.titleField) {
        if (string.length == 0) return YES;

        NSInteger existedLength = textField.text.length;
        NSInteger selectedLength = range.length;
        NSInteger replaceLength = string.length;
        if
(existedLength - selectedLength + replaceLength > 20) { return NO; } } return YES; }

到這裡可能會覺得基本大功告成了,但是當你輸入19個字元後,第20個字元以中文漢字的形式繼續輸入,那麼系統會在鍵盤上方提供後續的一系列聯想詞,你會發現通過這種方式可以連續選字輸入從而突破20個字元的限制。WTF

到了這裡,我們可能會希望有個類似

- (void)textFieldDidChange:(UITextField *)textField

的回撥方法,但可惜沒有。
當然,我們還可以通過

- (void)textFieldDidEndEditing:(UITextField *)textField;

回撥方法在結束編輯的時候把文字截斷,雖然在使用者體驗上會有點突兀。
不過當我們點進去UITextField.h標頭檔案裡尋覓上述回撥方法而不得時,可能會發現最下面有這麼個訊息通知名稱:

UIKIT_EXTERN NSString *const UITextFieldTextDidChangeNotification;

不過,監聽訊息還要記得解除監聽,通常我還習慣把監聽訊息的程式碼統一放在一個方法中,看起來有點“大動干戈”。
所幸的是UITextField本身提供了相應的事件監聽

[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

這樣就可以更好地限制輸入長度:

- (void)textFieldDidChange:(UITextField *)textField
{
    if (textField == self.titleField) {
        if (textField.text.length > 20) {
            textField.text = [textField.text substringToIndex:20];
        }
    }
}