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"(注意末尾的小数点),不仅能保护此格式化器,对用户也有好处。