EditText限制輸入的幾種方式及只顯示中文漢字的做法

前段時(shí)間項(xiàng)目中有個(gè)需求是要求只能輸入漢字揍愁,并且不能輸入偏旁部首臂寝,于是總結(jié)了下EditText限制輸入的幾種方式凳干,但是對(duì)于語(yǔ)音輸入的還沒(méi)找到好的解決方案:

  1. 通過(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)容锐帜。

  1. 通過(guò)設(shè)置EditText的android:digits 屬性來(lái)限制可輸入的內(nèi)容田盈,但需要把允許輸入的內(nèi)容全都羅列出來(lái),只適合允許輸入少數(shù)限制的情況缴阎,如只允許輸入數(shù)字允瞧,像這種只能輸入漢字的情況明顯不適合,總不能把幾千個(gè)漢字全都羅列出來(lái)吧蛮拔。

  2. 通過(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;
            }
        }

        ...
    }
  1. 通過(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 = "[犭凵巛冖氵廴纟讠礻亻钅宀亠忄辶弋饣刂阝冫卩疒艸疋豸冂匸扌丬屮衤勹彳彡]";
  1. 通過(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)重新拼接在一起返回。如果有朋友有好的解決方案朝捆,還望不吝賜教般渡!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芙盘,隨后出現(xiàn)的幾起案子驯用,更是在濱河造成了極大的恐慌,老刑警劉巖何陆,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晨汹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贷盲,警方通過(guò)查閱死者的電腦和手機(jī)淘这,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)剥扣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人铝穷,你說(shuō)我怎么就攤上這事钠怯。” “怎么了曙聂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵晦炊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宁脊,道長(zhǎng)断国,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任榆苞,我火速辦了婚禮稳衬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坐漏。我一直安慰自己薄疚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布赊琳。 她就那樣靜靜地躺著街夭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪躏筏。 梳的紋絲不亂的頭發(fā)上板丽,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音寸士,去河邊找鬼檐什。 笑死,一個(gè)胖子當(dāng)著我的面吹牛弱卡,可吹牛的內(nèi)容都是我干的乃正。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼婶博,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瓮具!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起凡人,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤名党,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后挠轴,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體传睹,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年岸晦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了欧啤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睛藻。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖邢隧,靈堂內(nèi)的尸體忽然破棺而出店印,到底是詐尸還是另有隱情,我是刑警寧澤倒慧,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布按摘,位于F島的核電站,受9級(jí)特大地震影響纫谅,放射性物質(zhì)發(fā)生泄漏炫贤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一系宜、第九天 我趴在偏房一處隱蔽的房頂上張望照激。 院中可真熱鬧,春花似錦盹牧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至苹粟,卻和暖如春有滑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嵌削。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工毛好, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人苛秕。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓肌访,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親艇劫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吼驶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353