Android實現輸入手機號時自動添加空格

背景

爲了優化用戶體驗,我們往往會在讓用戶輸入手機號碼時添加空格,比如: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時分別加上空格.

驗證需求

運行程序得到結果如下:

更多文章請移步我的博客:DevWiki’s Bolg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章