TextWatcher作用為監(jiān)測鍵盤輸入并根據(jù)輸入內(nèi)容展示不同顯示效果
接口分析(按回調(diào)順序)
- 文本改變前
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
其中有4個參數(shù):
-
CharSequence s
:文本改變之前的內(nèi)容 -
int start
: 被替換文本區(qū)域起點位置 -
int count
:將被替換的文本區(qū)域字符數(shù)目 -
int after
:替換后的文本字符數(shù)目
文本 s 中的 start 位置之后的 count 個字符將被替換為 after 個新的字符
注:s為替換前的文本
- 文本改變時
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
其中有4個參數(shù):
-
CharSequence s
:文本改變之后的內(nèi)容 -
int start
: 被替換文本區(qū)域起點位置,setText時是替換所有內(nèi)容,此時數(shù)值為0 -
int before
:被替換之前的文本區(qū)域字符數(shù)目 -
int count
:替換后的文本字符數(shù)目
文本 s 中的 start 位置之后的 before 個字符已經(jīng)被替換為 count 個新的字符
注:s為替換后的新文本
- 文本改變后
@Override
public void afterTextChanged(Editable s) {}
其中有1個參數(shù):
-
Editable s
:文本改變之后的內(nèi)容
TextWatcher使用
//所有繼承自TextView的類
textView.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable s) {}
});
注意事項 :
- 在回調(diào)方法中獲取的新字符串雖然已經(jīng)設(shè)置到
TextView
中,但是還未在UI界面中更新.
重要 :
經(jīng)網(wǎng)上查閱,幾乎沒有人提到過回調(diào)方法過程中UI是否已經(jīng)更新數(shù)據(jù),而筆者比較在意是否處理數(shù)據(jù)導(dǎo)致頁面閃爍.
發(fā)現(xiàn)有人已經(jīng)注意到這一點,其情景為短時間內(nèi)多次觸發(fā)回調(diào),但是頁面只顯示了最后一次數(shù)據(jù)結(jié)果,而評論中卻歸結(jié)為處理速度快導(dǎo)致分辨不出閃爍.
筆者在回調(diào)方法中加入延時,而UI更新時間為3個回調(diào)方法結(jié)束后.判斷為只有在數(shù)據(jù)處理完畢后才會顯示在UI上.
如若判斷失誤歡迎大家指正
- 有2種情況會觸發(fā)TextWatcher的3個回調(diào)方法,
setText()
和EditText
鍵盤輸入 - 如果在回調(diào)方法中調(diào)用
setText()
,會進入無限循環(huán),需要增加判斷條件 -
afterTextChanged
中去改變Editable s
的值會觸發(fā)TextWatcher的3個回調(diào)方法,會進入無限循環(huán),需要增加判斷條件 -
Editable s
和CharSequence s
獲取的數(shù)據(jù)為去除空格和回車之后字符串.
應(yīng)用場景
- 各種銀行卡/激活碼/手機號/電話號等等輸入框,可根據(jù)輸入的內(nèi)容進行添加空格,破折號或加號等等,形成格式化.
- 對于微博,微信朋友圈等等場景多半對于字符串長度有要求,而直觀的加入字?jǐn)?shù)顯示和剩余字?jǐn)?shù)可提升用戶體驗.
- 特殊場景,比如輸入銀行卡時只能輸入數(shù)字,身份證只能輸入數(shù)字+X,輸入激活碼時全部大寫等等.
- 輸入聯(lián)想,輸入補全等等,例如商品搜索過程自動改變listview內(nèi)容,例如輸入郵箱過程中檢測到@時自動顯示常用后綴等等.
- 拋磚引玉,歡迎大家發(fā)掘更多應(yīng)用場景
InputFilter過濾
InputFilter是系統(tǒng)提供的一個接口,是一個過濾器,修改傳入的字符串,返回值類型為CharSequence.
自定義InputFilter
public class mInputFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
return null;
}
}
可以看到只需要實現(xiàn)filter()
方法,而方法會傳入6個參數(shù),下面詳細解釋每個參數(shù)的含義
-
CharSequence source
用來替換的新的字符串,包括鍵盤輸入/setText()
/粘貼的內(nèi)容 -
int start
source的起始位置 -
int end
source的結(jié)束位置
以上3個參數(shù)描述出用來替換的新的字符串 -
Spanned dest
修改前的字符串,setText()
時dest
為EMPTY_SPANNED
,添加或修改時為輸入框內(nèi)的文本內(nèi)容 -
int dstart
dest選中范圍的起始位置 -
int dend
dest選中范圍的結(jié)束位置
textView.setFilters(inputFilters);
設(shè)置過濾器,inputFilters
為InputFilter
數(shù)組.
注意事項
-
setFilters
方法為替換過程,如果直接添加我們自定義的過濾器會導(dǎo)致原本textview自帶的過濾方法失效,比如設(shè)置了maxLength
屬性會無效.具體方法如下
//獲取到原來的InputFilter數(shù)組
textView.getFilters();
... //將獲取到的InputFilter數(shù)組元素加入新建的數(shù)組中
//設(shè)置新的
textView.setFilters(inputFilters);
- 過濾操作在
beforeTextChanged
回調(diào)方法之前進行 - 過濾操作是對InputFilter數(shù)組的元素進行遍歷,需要考慮元素順序?qū)^濾的影響
int n = mFilters.length;
for (int i = 0; i < n; i++) {
CharSequence out = mFilters[i].filter(text, 0, text.length(), EMPTY_SPANNED, 0, 0);
if (out != null) {
text = out;
}
}
根據(jù)源碼得知,當(dāng)返回值為null時,不對輸入數(shù)據(jù)進行任何過濾操作,數(shù)據(jù)不變