前段時(shí)間項(xiàng)目中有個(gè)需求是要求只能輸入漢字揍愁,并且不能輸入偏旁部首臂寝,于是總結(jié)了下EditText限制輸入的幾種方式凳干,但是對(duì)于語(yǔ)音輸入的還沒(méi)找到好的解決方案:
- 通過(guò)設(shè)置EditText的inputType來(lái)限制彰阴,可以在xml或者java代碼中設(shè)置:
在xml中設(shè)置:android:inputType="textPassword"
在java代碼中設(shè)置: mEditText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
可以通過(guò)設(shè)置不同屬性來(lái)限制輸入內(nèi)容锐帜。
通過(guò)設(shè)置EditText的
android:digits
屬性來(lái)限制可輸入的內(nèi)容田盈,但需要把允許輸入的內(nèi)容全都羅列出來(lái),只適合允許輸入少數(shù)限制的情況缴阎,如只允許輸入數(shù)字允瞧,像這種只能輸入漢字的情況明顯不適合,總不能把幾千個(gè)漢字全都羅列出來(lái)吧蛮拔。通過(guò)InputFilter來(lái)限制述暂。
/**
* EditText限制只能輸入漢字
*/
public InputFilter getInputFilter() {
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
if (TextUtils.isEmpty(source)){
return "";
}
for (int i = start; i < end; i++) {
if (stringFilterChinese(source) && !source.toString().contains("。") && !source.toString ().contains("建炫,")) {
return "";
} else if (CHINESE_RADICAL_DIGISTS.contains(source)) {
return "";
}
}
return null;
}
};
return filter;
}
/**
* 限制只能輸入漢字畦韭,過(guò)濾非漢字
*
* @param str 輸入值
* @return true 非漢字;false 漢字
*/
public boolean stringFilterChinese(CharSequence str) {
//只允許漢字肛跌,正則表達(dá)式匹配出所有非漢字
String regEx = "[^\u4E00-\u9FA5]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
if (m.find()) {
return true;
} else {
return false;
}
}
mEdtAddDictation.setFilters(new InputFilter[]{getInputFilter()});
查看TextView的源碼艺配,在setText中通過(guò)調(diào)用filter()過(guò)濾了相關(guān)內(nèi)容:
private void setText(CharSequence text, BufferType type,boolean notifyBefore, int oldlen) {
...
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;
}
}
...
}
- 通過(guò)TextWatch來(lái)限制輸入察郁。
mEdtAddDictation.addTextChangedListener(mTextWatcher);
private TextWatcher mTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
this.temp = s;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable editable) {
String words = editable.toString().trim();
if (TextUtils.isEmpty(words)) {
mBtnAddSure.setEnabled(false);
} else {
mBtnAddSure.setEnabled(true);
}
if (TextUtils.isEmpty(words)) {
return;
}
String newWords = words;
newWords = StringUtils.clearLimitStr(StringUtils.DEFAULT_REGEX_LIMIT_CHINESE,newWords);
newWords = StringUtils.clearLimitStr(StringUtils.CHINESE_RADICAL_DIGISTS,newWords);
boolean isChange = false;
if (!TextUtils.equals(words,newWords)){
isChange = true;
words = newWords;
}
if (words.length() > MAX_INPUT_LIMIT) {
ToastUtils.getInstance(AddDictationWordsActivity.this).s(R.string.dictation_add_word_limit);
words = words.substring(0, MAX_INPUT_LIMIT);
isChange = true;
}
if (isChange) {
mEdtAddDictation.removeTextChangedListener(this);
// et.setText方法可能會(huì)引起鍵盤(pán)變化,所以用editable.replace來(lái)顯示內(nèi)容
editable.replace(0, editable.length(), words.trim());
mEdtAddDictation.addTextChangedListener(this);
}
}
};
/**
* 清除不符合條件的內(nèi)容
*
* @param regex
* @return
*/
public static String clearLimitStr(String regex, String str) {
return str.replaceAll(regex, "");
}
/**
* 默認(rèn)的篩選條件(正則:只能輸入中文)
*/
public static String DEFAULT_REGEX_LIMIT_CHINESE = "[^\u4E00-\u9FA5]";
/**
* 偏旁部首
*/
public static final String CHINESE_RADICAL_DIGISTS = "[犭凵巛冖氵廴纟讠礻亻钅宀亠忄辶弋饣刂阝冫卩疒艸疋豸冂匸扌丬屮衤勹彳彡]";
- 通過(guò)自定義InputConnectionWrapper來(lái)限制輸入。
步驟:
(1)自定義EditText转唉,重載onCreateInputConnection方法皮钠,它需要返回一個(gè)InputConnection對(duì)象;
(2)繼承于InputConnectionWrapper酝掩, 實(shí)現(xiàn)自己的InputConnection 并且在onCreateInputConnection中返回鳞芙。
(3)在自定義的InputConnectionWrapper類中,實(shí)現(xiàn)輸入法輸入和按鍵事件的攔截。
由于InputConnection是在文本顯示之前進(jìn)行調(diào)用,因此可以通過(guò)重寫(xiě)其中的方法修改要顯示的內(nèi)容甚牲。
/**
* @author zhangshao
* @desc 只能輸入漢字的輸入框
* @time 2018/11/8 18:09
*/
@SuppressLint("AppCompatCustomView")
public class ChineseLimitEditText extends EditText {
public ChineseLimitEditText(Context context) {
super(context);
}
public ChineseLimitEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ChineseLimitEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 輸入法
*
* @param outAttrs
* @return
*/
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return new InnerInputConnecttion(super.onCreateInputConnection(outAttrs),
false);
}
class InnerInputConnecttion extends InputConnectionWrapper implements InputConnection {
public InnerInputConnecttion(InputConnection target, boolean mutable) {
super(target, mutable);
}
/**
* 對(duì)輸入的內(nèi)容進(jìn)行攔截
*
* @param text
* @param newCursorPosition
* @return
*/
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
// 只能輸入漢字
if (!TextUtils.isEmpty(text) && (!StringUtils.isContainChinese(text.toString()) ||
StringUtils.isContainRadical(text.toString()))) {
return false;
}
return super.commitText(text, newCursorPosition);
}
@Override
public boolean sendKeyEvent(KeyEvent event) {
// 攔截?fù)Q行鍵
return event.getKeyCode() != KeyEvent.KEYCODE_ENTER && super.sendKeyEvent(event);
}
@Override
public boolean setSelection(int start, int end) {
return super.setSelection(start, end);
}
}
}
/**
* 字符串是否包含中文
* */
public static boolean isContainChinese(String str) {
Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
Matcher m = p.matcher(str);
if (m.find()) {
return true;
}
return false;
}
/**
* 字符串是否包含偏旁部首
* */
public static boolean isContainRadical(String str) {
Pattern p = Pattern.compile(CHINESE_RADICAL_DIGISTS);
Matcher m = p.matcher(str);
if (m.find()) {
return true;
}
return false;
}
攔截條件:在commitText方法中陕靠,如果執(zhí)行父類的 commitText(即super.commitText(text, newCursorPosition))那么表示不攔截,如果返回false則表示攔截鞠评,
輸入法的字符串則無(wú)法傳送到EditText茂蚓。在sendKeyEvent中,如果執(zhí)行父類的sendKeyEvent(即super.sendKeyEvent(event))那么表示不攔截剃幌,如果返回false表示攔截聋涨。
不同的需求可以通過(guò)不同的限制方法組合使用,不用局限于一種负乡。
以上幾種方法都可以解決軟鍵盤(pán)輸入時(shí)只顯示中文的問(wèn)題牍白,但是搜狗輸入法的語(yǔ)音輸入無(wú)法過(guò)濾,一旦在InputFilter或者TextWatch中屏蔽抖棘,那么語(yǔ)音輸入內(nèi)容會(huì)重復(fù)茂腥,目前分析的原因是:語(yǔ)音輸入是持續(xù)輸入,如果去掉相應(yīng)的標(biāo)點(diǎn)切省,那么輸入法會(huì)檢測(cè)到輸入內(nèi)容與緩存的不對(duì)應(yīng)最岗,會(huì)把之前的文本拿出來(lái)重新拼接在一起返回。如果有朋友有好的解決方案朝捆,還望不吝賜教般渡!