android 之EditText輸入檢測
最近開發一個功能的時候發生一個故事,其情節如下:
功能其實不復雜,其中需要一個EditText來獲取使用者輸入的資訊.於是,我做了一個Dialog來顯示我的輸入介面(程式碼如下):
mAlertDialog = new AlertDialog.Builder(this)//, android.R.style.Theme_Holo_Light .setIcon(R.drawable.ic_dialog_info_light) .setTitle(R.string.model_rename_device) .setView(createDialogView(deviceName)) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //String deviceName = mDeviceNameView.getText().toString(); reset_success=false; reset_model_name(mDeviceNameView.getText().toString()); //finish(); } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //finish(); } }) .setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface arg0) { if(reset_success){ start_confir_ResetPhone(); }else{ finish(); } } }) .create(); mAlertDialog.getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); mAlertDialog.show();
實現起來很簡單!不過當我把使用者輸入的字串儲存起來時候,問題就來了!private View createDialogView(String deviceName) { final LayoutInflater layoutInflater = (LayoutInflater)this .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = layoutInflater.inflate(R.layout.dialog_edittext, null); mDeviceNameView = (EditText) view.findViewById(R.id.edittext); mDeviceNameView.setFilters(new InputFilter[] { new Utf8ByteLengthFilter(MODEL_NAME_MAX_LENGTH_BYTES) }); mDeviceNameView.setText(deviceName); // set initial value before adding listener mDeviceNameView.addTextChangedListener(this); mDeviceNameView.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { reset_model_name(v.getText().toString()); mAlertDialog.dismiss(); //finish(); return true; // action handled } else { //finish(); return false; // not handled } } }); mDeviceNameView.setSelection(mDeviceNameView.length()); return view; }
原來這個使用者輸入的字串需要儲存在一段我們自己配置的nv裡面,重要的是,分給我儲存的字串的空間只有20個byte,沒有錯就是byte. 所以很簡單,輸入的字元最多不能超過20個字元,由於是byte型別,所以對於輸入的字元必須做檢測,其字元必須在一個byte取值空間(0-127)裡面.實際上就是asic碼.
所以需要對輸入的字元檢測.
為了能夠實時檢測EditText輸入的字元你需要EditText.addTextChangedListener()來新增一個TextWatcher的檢測器,並且實現其中的方法:
public void afterTextChanged(Editable s)
public void beforeTextChanged(CharSequence s, int start, int count, int after)
public void onTextChanged(CharSequence s, int start, int before, int count)
首當其衝想到的辦法是在afterTextChanged方法裡面判斷當前輸入的字元是否時正確的字元,如果不是就通過Editable s來更改:s.delete()來刪除.或者直接使用這個EditText的去從新設定輸入的字元:setText();
其實,這兩個辦法都不行,當快速輸入不對的字元時候就會出現異常,很顯然時同步的問題.
很快我給出來另個解決方法:在onTextChanged()裡面檢測是否有異常的字元,如果有則通過Handler傳送訊息的形式來處理.
public void onTextChanged(CharSequence s, int start, int before, int count) {
for(int i=0; i < count; i++){
if(s.charAt(i+start) > 127 || s.charAt(i+start) < 0){
Message msg = mHandler.obtainMessage(handleMessage_detection_MG);
msg.obj = s;
mHandler.sendMessage(msg);
break;
}
}
//Log.d(DEBUG_STR,"onTextChanged str="+s.toString()+"start="+start+"; before="+before+"; count="+count);
}
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case handleMessage_detection_MG:
InptText_Error_correction((CharSequence) msg.obj);
break;
case handleMessage_blue_name_MG:
InptText_rename_blue((String) msg.obj);
break;
default:
break;
}
}
};
private void InptText_Error_correction(CharSequence chars){
if(chars != null){
StringBuilder str_b = new StringBuilder(chars);
char temp;
int start_indx = -1;
for(int i = 0; i < str_b.length(); i++){
temp = str_b.charAt(i);
if(temp > 127 || temp < 0){
if(start_indx < 0){
start_indx = i;
}
str_b.deleteCharAt(i);
}
}
mDeviceNameView.setText(str_b.toString());
if(start_indx < 0){
start_indx = mDeviceNameView.length();
}
mDeviceNameView.setSelection(start_indx);
Toast.makeText(Rename_model_activity.this, getString(R.string.set_name_Error_Character_notice),
Toast.LENGTH_SHORT).show();
}
}
最後要說的是:對於輸入字元的限制可以通過EditText.setFilters()來配置:
mDeviceNameView.setFilters(new InputFilter[] {
new Utf8ByteLengthFilter(MODEL_NAME_MAX_LENGTH_BYTES)
});
MODEL_NAME_MAX_LENGTH_BYTES時輸入字元的最大長度,Utf8ByteLengthFilter是InputFilter的子類.這裡就是對輸入長度的適配.
其實你會很快發現!InputFilter就是一個對輸入字元的檢測器.所以對於輸入字元錯誤檢測其實不用那麼麻煩,其實InputFilter完全可以解決.實現他的方法:
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend)
對於輸入的錯誤字元,位元組返回""就可以:
for (int i = start; i < end; i++) {
char c = source.charAt(i);
if(c > 127 || c < 0){
return "";
}
}