10.監控TextView的變動
10.1 問題
應用程式需要持續監控TextView小部件(例如EditText)中文文字內容的變動情況。
10.2 解決方案
(API Level 2)
實現android.text.TextWatcher介面。textWatcher提供了3個文字更新過程中的回撥方法:
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);
beforeTextChanged()和onTextChanged()方法主要用於提供提示功能,因為這兩個方法實際上都無法修改CharSequence。如果要截獲檢視中輸入的文字,當afterTextChanged()方法被呼叫時文字就有可能發生了變化。
10.3 實現機制
呼叫TextView.addTextChangedListener()方法將TextWatcher註冊到TextView。注意,根據語法,可以將多個TextWatcher註冊到一個TextView。
1. 字元計數器示例
TextWatcher的一個簡單應用是建立EditText的字元計數器,能隨著使用者的輸入和刪除操作實時顯示其中的字數。以下程式碼清單中的示例Activity就實現了這樣一個TextWatcher,註冊了一個EditText小部件並在Activity的標題上顯示字元數。
字元計數器Activity
public class MyActivity extends Activity implements TextWatcher { EditText text; int textCount; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //建立EditText 小部件並新增監控器 text = new EditText(this); text.addTextChangedListener(this); setContentView(text); } /* 實現TextWatcher的方法 */ public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int end) { textCount = text.getText().length(); setTitle(String.valueOf(textCount)); } public void afterTextChanged(Editable s) { } }
因為不需要修改使用者正在輸入的文字,所以可以呼叫onTextChanged()方法以獲得字數,只要使用者輸入的文字發生變化就會回撥該方法。其他的方法暫時沒用,留空即可。
2. 貨幣符號格式化示例
SDK中有一些很方便的用於格式化文字輸入的預定義TextWatcher例項;PhoneNumberFormattingTextWatcher就是其中之一。這些例項的任務就是在使用者輸入時將其按標準格式化,減少輸入規範化資料的擊鍵次數。
在以下程式碼清單中,我們建立了一個CurrencyTextWatcher,在TextView中插入貨幣符號和分隔點。
貨幣符號格式器
public class CurrencyTextWatcher implements TextWatcher { boolean mEditing; public CurrencyTextWatcher() { mEditing = false; } public synchronized void afterTextChanged(Editable s) { if(!mEditing) { mEditing = true; //strip符號 String digits = s.toString().replaceAll("\\D", ""); NumberFormat nf = NumberFormat.getCurrencyInstance(); try{ String formatted = nf.format(Double.parseDouble(digits)/100); s.replace(0, s.length(), formatted); } catch (NumberFormatException nfe) { s.clear(); } mEditing = false; } } public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { } }
注意:
在afterTextChanged()方法中修改Editable的值會導致TextWatcher方法被再次呼叫(因為剛剛修改了文字)。考慮到這一點,在實現自定義TextWatcher時,應該通過某個布林變數或是其他跟蹤機制來判斷文字修改的來源,避免產生無限迴圈。
我們可以將這個自定義的文字格式化器應用於Activity中的EditText(參見以下程式碼清單)。
使用貨幣符號格式化器的Activity
public class MyActivity extends Activity { EditText text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); text = new EditText(this); text.addTextChangedListener(new CurrencyTextWatcher()); setContentView(text); } }
使用這個格式化器格式化使用者輸入,就可以很方便地在XML中定義EditText的android:inputType和android:digits約束來格式化使用者的輸入,從而保護欄位不受輸入錯誤的影響。特別是,為EditText加上android:digits = "0123456789"(注意末尾的小數點),不僅能保護此格式化器,對使用者也有好處。