TextField 輸入身份證號手機號銀行卡號格式化解決方案

老JI發表於2018-01-10

問題描述

TextField中輸入身份證號,手機號,銀行卡號時每隔幾位需要新增空格。當輸入錯誤時需要從末尾或者中間刪除,刪除之後還要保持當前textfield的中內容保持每隔幾位就有一個空格的格式。這篇文章主要是為了解決這個問題

解決上面的問題主要要解決兩個點:

  1. 游標的位置
  2. 空格的位置

上面的兩種情況又可以分為:

  • 從最後一位刪除
  • 從中間刪除
  • 一次刪除一個和多個
  • 從最後一位新增
  • 從中間新增
  • 一次新增一位和多位

這幾種情況都要考慮游標的位置和空格的位置,每次新增和刪除都要重新計算.

實現:

首先詳細說下?的這個代理方法:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
複製程式碼
range

shouldChangeCharactersInRange :有location 和length 兩個引數 location 是即將被替代的內容的位置 length 是即將被替代的內容的長度

string

用來替代在range位置內容的字串

假如:textfield中有內容為1234

三種情況解釋下string 和range引數 :

  1. 游標在最後一位時刪除一位 :那麼string就是為空 range的location 就是游標前面的內容的下標即為3 length就是1 表示被刪除的內容長度為1 ,結果是string佔據了range表示的位置 即123,3後面的4被空字串佔據了即被刪除了
  2. 游標在最後一位刪除兩位:操作,長按textfield選中23,點選刪除。可以發現string依舊為空 ,range變為 location=1, length=2 即位置在下標為1 長度為2的字串被空字串替代了,還剩1,所謂的23被刪除了
  3. 新增一個:游標在最後一位。輸入一個2,此時range:location為1,length為0 即被替代的內容位置在下標為1的地方,長度是空。string為2,那麼結果就是一個下標為1,長度為0的字串被string替代了,即textfield內容新增了一個2,複製到textfield中的內容range 和 string 也是同樣的適用

說的這麼詳細主要為下一步做準備。

UITextInput協議 中的幾個屬性和方法

設定游標的位置需要下面的兩個方法


// 獲取以fromPosition為基準偏移offset的游標位置。
- (nullable UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset;
// 建立一個UITextRange
- (nullable UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition;

複製程式碼

設定游標位置的方法

根據UITextInput協議的兩個方法可以得出設定游標的位置的方法

+ (void)setCursorLocation:(UITextField *)textField withOffset:(NSInteger) offset{
    // offset 游標要所處的位置
    // 生成新的postion
    UITextPosition *newPostion = [textField positionFromPosition:textField.beginningOfDocument offset:offset] ;
    //設定游標 從一個點到另外一個點如果兩個點一樣 那麼游標就在這個點
    textField.selectedTextRange = [textField textRangeFromPosition:newPostion toPosition:newPostion];
}
複製程式碼

注意:在textField中,有一個屬性稱之為selectedTextRange,這個屬性為UITextRange型別,包含[start,end)兩個值,通過實驗可以發現,在沒有文字被選取時,start 和 end的值一樣 代表當前游標的位置;當有區域被選擇時,start和end分別是選擇的頭和尾的游標位置

可以看出 setCursorLocation 方法中很重要的一個引數是偏移量

新增空格的方法

// 在指定的位置新增空格
+(NSString*)insertString:(NSString*)string withBlankLocations:(NSArray<NSNumber *>*)locations {
    if (!string) {
        return nil;
    }
    NSMutableString* mutableString = [NSMutableString stringWithString:[string stringByReplacingOccurrencesOfString:@" " withString:@""]];
    for (NSNumber *location in locations) {
        if (mutableString.length > location.integerValue) {
            [mutableString insertString:@" " atIndex:location.integerValue];
        }
    }
    return  mutableString;
}
複製程式碼

上面這個方法是根據傳入的空格的位置,遍歷整個字串,在指定的位置為字串新增一個空格. 這個方法呼叫的時機就是 textField 中的 text 發生改變時呼叫,比如說刪除或者增加字串

那麼以下就根據不同的情況來計算偏移量設定游標 和 新增空格

刪除字串

如何判斷是點選了鍵盤的刪除

如上面所說 在

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
複製程式碼

這個代理方法中 當string為空時就是刪除。range是一個位置表示string的位置 如果string為空時 range.length 表示刪除的長度

  1. 刪除一位 如果 range.length == 1 如果string 為空 且 range的location 為當前textField.text的長度減一 即location是textField.text的最後一個字元時 表示在最後一位刪除

① 如果在最後一位刪除一位不需要設定游標的位置和新增空格

② 如果不是最後一位刪除一位則要判斷刪除的是不是空格。如果是空格則會連續刪除兩次

// 不是最後一位
                        NSInteger locationOffset = range.location;
                        if (range.location < text.length && [text characterAtIndex:range.location] == ' ' && [textField.selectedTextRange isEmpty]) {
                            [textField deleteBackward]; // 刪除空格
                            locationOffset --;
                        }
                        [textField deleteBackward];// 刪除空格前面的字元
複製程式碼

上面的程式碼呼叫了兩次[textField deleteBackward] 刪除了兩次

此時需要修改空格的位置和游標的位置,偏移量 offset 就是 range.location 的值 ,每刪除一位 offset 就要減1

  1. 刪除多位 同刪除一位的邏輯一樣 string為空切 range.length > 1 就表示一次刪除多位

① 是否是在最後一位開始刪除,如果再最後一位開始刪除那麼仍然不需要設定游標的位置,但是需要設定空格的位置

② 如果不是最後一位開始刪除,則需要計算游標的位置,偏移量仍然是當前 range.location

新增字串

如何判斷是新增?

如上面所說 在

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
複製程式碼

這個代理方法中 當string不為空時就是新增。range是一個位置表示string的位置 如果string不為空時 range.length 表示新增的字串的長度

如果所輸入的字串長度還沒有超出限制則直接新增到 textField 中然後在預定的位置新增空格

// 新增到textField 中 這個方法是 UIKeyInput 協議中的方法
[textField insertText:string];
//textField中的字串發生變化需要重新設定空格
textField.text = [self insertString:textField.text withBlankLocations:blankLocation];
複製程式碼

此時要計算偏移量 ,在計算是游標的位置是 range.location + string.length ,但是如果在游標位置出正好有空格則offset需要 +1 如下

NSInteger offset = range.location + string.length;
            
            for (NSNumber *location in blankLocation) {
                if (range.location == location.integerValue) {
                    offset ++;
                }
            }
            [self setCursorLocation:textField withOffset:offset];
複製程式碼

通過以上幾種情況就可以解決文章開頭描述的問題了.

Demo 在這裡 我是 Demo

轉載請註明出處 https://juejin.im/post/5a527443f265da3e324551ee 謝謝!

如果解決了您的問題,請點贊支援下哈!

輸入刪除銀行卡號效果圖

相關文章