Android實現輸入手機號時自動新增空格

DevWiki發表於2019-01-31

背景

為了優化使用者體驗,我們往往會在讓使用者輸入手機號碼時新增空格,比如:133 1234 5678.那麼在Android中如何實現呢?

實現方法

Android中的輸入框EditText有個方法addTextChangedListener(),該方法實現輸入框文字變動時的監聽.該方法需要傳入一個TextWatcher介面的實現.

TextWatcher介面如下:

public interface TextWatcher extends NoCopySpan {

    public void beforeTextChanged(CharSequence s, int start, int count, int after);

    public void onTextChanged(CharSequence s, int start, int before, int count);

    public void afterTextChanged(Editable s);
}
複製程式碼

該介面有三個回撥函式,其含義如下:

public abstract void beforeTextChanged (CharSequence s, int start, int count, int after):

This method is called to notify you that, within s, the count characters beginning at start are about to be replaced by new text with length after. It is an error to attempt to make changes to s from this callback. 在字串s內,從索引為start(包含)的字元開始的count個字元將被長度為after的新文字代替

public abstract void onTextChanged (CharSequence s, int start, int before, int count)

This method is called to notify you that, within s, the count characters beginning at start have just replaced old text that had length before. It is an error to attempt to make changes to s from this callback. 在字串s內,從索引為start(包含)的字元開始count個字元剛剛替換了長度為before的舊字元.;

public abstract void afterTextChanged (Editable s)

This method is called to notify you that, somewhere within s, the text has been changed. It is legitimate to make further changes to s from this callback, but be careful not to get yourself into an infinite loop, because any changes you make will cause this method to be called again recursively. (You are not told where the change took place because other afterTextChanged() methods may already have made other changes and invalidated the offsets. But if you need to know here, you can use setSpan(Object, int, int, int) in onTextChanged(CharSequence, int, int, int) to mark your place and then look up from here where the span ended up. 字串s內容已經發生了變化.可以在這一步對s進行合理的變更,但是要注意不要進入無限迴圈,因為字串的任何變化都會再次遞迴呼叫此回撥方法.在這個方法中不會告訴你字串哪些內容發生了變化,因為其他針對字串的改變已經呼叫了afterTextChanged().如果你想知道哪些發生了變化,可以在onTextChanged(CharSequence, int, int, int)使用setSpan(Object, int, int, int)做標記.

看上面的解釋,是不是還是有點糊塗呢?下面就用例項來解釋一下吧.

例項程式碼

程式碼很簡單,只有一個輸入框EditText,然後新增一個TextWatcher實現,將回撥中的結果輸出.

public class MainActivity extends AppCompatActivity {

    private EditText editText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText = (EditText) findViewById(R.id.edit_text);
        editText.addTextChangedListener(textWatcher);
    }

    private final TextWatcher textWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            DLog.d("----------beforeTextChanged----------\n");
            DLog.d("s:" + s + "\n");
            DLog.d("start:" + start + "\n");
            DLog.d("count:" + count + "\n");
            DLog.d("after:" + after + "\n");
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            DLog.d("----------onTextChanged----------\n");
            DLog.d("s:" + s + "\n");
            DLog.d("start:" + start + "\n");
            DLog.d("before:" + before + "\n");
            DLog.d("count:" + count + "\n");
        }

        @Override
        public void afterTextChanged(Editable s) {
            DLog.d("----------afterTextChanged----------\n");
            DLog.d("s:" + s + "\n");
        }
    };
}
複製程式碼

其中Dlog類參見此處:Android除錯Log二次包裝

輸出結果

預設輸入框沒有任何內容,以下操作在上一步之後進行.

輸入一個字元

在輸入框輸入字元:1,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:
start:0
count:0
after:1
//註釋:在字串""從索引0處開始的0個字元將被長度為1的新字串代替
//即""將被1代替
----------onTextChanged----------
s:1
start:0
before:0
count:1
//註釋:字串"1"從索引0處開始的1個字元剛剛替換了長度為0的舊字串
//即1剛剛代替了""
----------afterTextChanged----------
s:1
//註釋:發生變化後的字串為:"1"
複製程式碼

輸入兩個字元

在輸入框一次性輸入字元(即貼上):23,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:1
start:1
count:0
after:2
//註釋:在字串"1"從索引1開始的0個字元將被長度為2的新字串代替
//即""將被23代替
----------onTextChanged----------
s:123
start:1
before:0
count:2
//註釋:字串"123"從索引1開始的2個字元剛剛替換了長度為0的舊字串
//即23剛剛代替了""
----------afterTextChanged----------
s:123
//註釋:發生變化後的字串為:"123"
複製程式碼

輸入三個字元

在輸入框一次性輸入字元(即貼上):456,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:123
start:3
count:0
after:3
//註釋:在字串"123"從索引3開始的0個字元將被長度為3的新字串代替
//即""將被456代替
----------onTextChanged----------
s:123456
start:3
before:0
count:3
//註釋:字串"123456"從索引3開始的3個字元剛剛替換了長度為0的舊字串
//即456剛剛代替了""
----------afterTextChanged----------
s:123456
//註釋:發生變化後的字串為:"123456"
複製程式碼

刪除一個字元

在輸入框刪除字元:6,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:123456
start:5
count:1
after:0
//註釋:在字串"123456"從索引5開始的1個字元將被長度為0的新字串代替
//即6將被""代替
----------onTextChanged----------
s:12345
start:5
before:1
count:0
//註釋:字串"12345"從索引5開始的0個字元剛剛替換了長度為1的舊字串
//即""剛剛代替了6
----------afterTextChanged----------
s:12345
//註釋:發生變化後的字串為:"12345"
複製程式碼

刪除兩個字元

在輸入框一次性刪除字元:45,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:12345
start:3
count:2
after:0
//註釋:在字串"12345"從索引3開始的2個字元將被長度為0的新字串代替
//即45將被""代替
----------onTextChanged----------
s:123
start:3
before:2
count:0
//註釋:字串"123"從索引3開始的0個字元剛剛替換了長度為2的舊字串
//即""剛剛代替了45
----------afterTextChanged----------
s:123
//註釋:發生變化後的字串為:"123"
複製程式碼

將一個字元替換為兩個字元

在輸入框選中3貼上為ab,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:123
start:2
count:1
after:2
//註釋:在字串"123"從索引2開始的1個字元將被長度為2的新字串代替
//即3將被ab代替
----------onTextChanged----------
s:12ab
start:2
before:1
count:2
//註釋:字串"12ab"從索引2開始的2個字元剛剛替換了長度為1的舊字串
//即ab剛剛代替了3
----------afterTextChanged----------
s:12ab
//註釋:發生變化後的字串為:"12ab"
複製程式碼

將兩個字元替換為一個字元

在輸入框選中ab貼上為3,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:12ab
start:2
count:2
after:1
//註釋:在字串"12ab"從索引2開始的2個字元將被長度為1的新字串代替
//即ab將被3代替
----------onTextChanged----------
s:123
start:2
before:2
count:1
//註釋:字串"123"從索引2開始的1個字元剛剛替換了長度為2的舊字串
//即3剛剛代替了ab
----------afterTextChanged----------
s:123
//註釋:發生變化後的字串為:"123"
複製程式碼

任意位置插入一個字串

在輸入框中2的後面輸入5,各回撥方法輸出的資訊如下(註釋為作者後來新增):

----------beforeTextChanged----------
s:123
start:2
count:0
after:1
//註釋:在字串"123"從索引2開始的0個字元將被長度為1的新字串代替
//即""將被5代替
----------onTextChanged----------
s:1253
start:2
before:0
count:1
//註釋:字串"1253"從索引2開始的1個字元剛剛替換了長度為0的舊字串
//5剛剛代替了""
----------afterTextChanged----------
s:1253
//註釋:發生變化後的字串為:"1253"
複製程式碼

解決需求

從上面我們可以看出,在onTextChanged方法中字串已經發生變化,我們可以在此對使用者輸入的字串追加空格. 使用者是一個數字一個數字的輸入到輸入框中,那麼條件為:

字串s從索引start開始的1個字元剛剛替換了""

public void onTextChanged(CharSequence s, int start, int before, int count) {
    DLog.d("----------onTextChanged----------\n");
    DLog.d("s:" + s + "\n");
    DLog.d("start:" + start + "\n");
    DLog.d("before:" + before + "\n");
    DLog.d("count:" + count + "\n");

    if (count == 1){
        int length = s.toString().length();
        if (length == 3 || length == 8){
            editText.setText(s + " ");
            editText.setSelection(editText.getText().toString().length());
        }
    }
}
複製程式碼

當長度為3和8時分別加上空格.

驗證需求

執行程式得到結果如下:

Android實現輸入手機號時自動新增空格

更多文章請移步我的部落格:DevWiki's Bolg

相關文章