Android-EditText 樣式&軟鍵盤&輸入限制開發(fā)細(xì)節(jié)匯總

開發(fā)小日常

測試:能不能別一打開頁面,就彈出輸入鍵盤?
博主:好的,我看下,這點(diǎn)疏忽了。

測試:能不能別一打開頁面,就顯示光標(biāo)?這個(gè)可以不用替用戶決定順序
博主:好的

測試:你看這個(gè)光標(biāo)是不是有點(diǎn)粗?能調(diào)色嗎?
博主:嗯,可以。

測試:為啥退出這個(gè)頁面后,這個(gè)軟鍵盤還在的?
博主:真的嗎?來我看看。

測試:這個(gè)可以讓它只輸入數(shù)字嗎?
測試:這個(gè)可以讓它只能輸入字母嗎?
測試:這個(gè)可以讓它只能輸入字母和數(shù)字嗎?
測試:可以讓用戶只能輸入兩位小數(shù)嗎?
測試:這個(gè)是手機(jī)號,可以限制最多 11 位嗎?
博主:.....

以上是一個(gè)真實(shí)的故事,感受最深刻的就是,就一個(gè)編輯框 ,細(xì)節(jié)真的不少,撇去導(dǎo)致這個(gè)問題的其他因素,今天的博客是一篇以 EditText 為主題 ,記錄修改能滿足以上各種需求的干貨文章。

EditText 相關(guān)知識點(diǎn)梳理

首先做個(gè)大概的了解,EditText 作為一個(gè)編輯框,UI考慮上可分為以下幾點(diǎn):

  • 編輯框本身的樣式。例如背景和光標(biāo),字體顏色大小等。
  • 軟鍵盤。例如彈出或關(guān)閉,顯示搜索或確定。
  • 輸入限制。例如限制輸入字母或者數(shù)字。

EditText 的樣式

這個(gè)在寫 xml 布局文件的階段會涉及到,Android 系統(tǒng)原生的編輯框,丑到開發(fā)者自己都看不下去,雖然在 Material Design 風(fēng)格出來之后好了很多,但是實(shí)際的項(xiàng)目開發(fā)中,Android 要和 iOS 保持統(tǒng)一,所以還是要自定義。

一般情況下是這種

image

和這種

image

以及等等。

設(shè)置字體顏色大小基本使用,我就不拿出來侮辱大家智商了,來點(diǎn)實(shí)際的:

EditText 背景
通過設(shè)置 android:background 完成。

不需要背景,設(shè)置android:background=“@null”
需要特殊的背景話,就可以通過這個(gè)設(shè)置啦。

EditText 內(nèi)置的小圖標(biāo)
例如上圖左邊的放大鏡小圖標(biāo)那種,可以通過 android:drawableLeft 設(shè)置小圖標(biāo), android:drawablePadding設(shè)置小圖標(biāo)和輸入字體的間距。

需要注意的是通過這種方式添加的小圖標(biāo),大小是沒法明確設(shè)置的,如果有額外要求,還是專門使用一個(gè)控件吧。

EditText 的光標(biāo)

EditText 的光標(biāo)顏色默認(rèn)是 colorAccent 的顏色, colorAccent不僅僅代表到光標(biāo)的顏色,還有項(xiàng)目中很多原生控件激活選擇時(shí)的顏色,所以 UI 上如果對編輯框光標(biāo)顏色有需求,無法直接修改 colorAccent ,或者認(rèn)為光標(biāo)太粗了,想改細(xì)一點(diǎn),這類情況都需要設(shè)置光標(biāo)的樣式。

例如設(shè)置光標(biāo)為藍(lán)色,寬度為 1 dp,需要先寫一個(gè)光標(biāo)樣式文件:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size android:width="1dp" />
    <solid android:color="#217aff" />
</shape>

然后通過 android:textCursorDrawable 引入這個(gè)光標(biāo)樣式。

android:textCursorDrawable="@drawable/edit_cursor_color"

另外:

android:cursorVisible 改變光標(biāo)的可見性
setSelection()可以改變光標(biāo)的位置。

關(guān)于軟鍵盤

編輯框和軟鍵盤的密不可分,如果不做任何設(shè)置,頁面上EditText 會默認(rèn)搶占焦點(diǎn),彈出軟鍵盤。有的頁面是這個(gè)需求,有的則不是,按需選擇。

EditText 不顯示光標(biāo),只有在點(diǎn)擊時(shí)才彈出軟鍵盤

這個(gè)在 xml 布局中給 EditText 的父布局設(shè)置觸摸獲取焦點(diǎn)可以解決,設(shè)置屬性是 android:focusableInTouchMode="true"

示例:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:focusableInTouchMode="true" >
    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
</LinearLayout>

經(jīng)驗(yàn)證,這個(gè)屬性,并非只有在設(shè)置直接父級布局上有效,在間接父級布局上也可以。但是設(shè)置在 ScrollView 父級布局上無效。

軟鍵盤在頁面退出時(shí),不自動關(guān)閉

這個(gè)情況是,最近發(fā)現(xiàn)的一個(gè)很搞笑的現(xiàn)象。頁面跳轉(zhuǎn)路徑是 A->B ,B中有 EditText,在彈出軟鍵盤后,不通過手機(jī)自帶的返回鍵,而是按 B 頁面中的返回按鈕回到 A 時(shí),發(fā)現(xiàn)軟鍵盤并未隨著B頁面自動關(guān)閉。

原因是 A 頁面設(shè)置了 android:windowSoftInputMode 設(shè)置了 stateHidden屬性。

<activity
            android:name="xxxxxxx"
            android:windowSoftInputMode="adjustPan|stateHidden"/>

解決方法是修改A頁面的 windowSoftInputMode 設(shè)置,一下是一個(gè)良心網(wǎng)友@zhangziki自測出來的表格,大家自己設(shè)置。

windowSoftInputMode 鍵盤是否自動收回
默認(rèn)不指定
stateUnspecified
stateAlwaysVisible
stateUnchanged ×
stateHidden ×
stateAlwaysHidden ×
stateVisible ×
stateHidden ×
stateHidden ×

設(shè)置軟鍵盤的 enter 鍵

默認(rèn)的鍵盤的 enter 是換行鍵,如下:

image

但是有的時(shí)候,產(chǎn)品需求會要求,鍵盤的 enter 鍵改為其他文字,最常見的是搜索,點(diǎn)擊搜索后出發(fā)代碼中設(shè)置的搜索邏輯。

image

通過在設(shè)置 EditText 的 imeOptions 可以改變 enter 鍵的文案,要著重說明的是,因?yàn)閷⒛J(rèn)的換行鍵換為了搜索鍵,所以等于放棄了換行功能,所以需要通知設(shè)置 android:singleLine="true" 才能使 android:imeOptions="actionSearch" 生效。

<EditText
          android:id="@+id/editText"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:singleLine="true"
          android:imeOptions="actionSearch"/>

代碼中可以通過這個(gè)方法設(shè)置監(jiān)聽:

mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                switch (actionId) {
                    case EditorInfo.IME_ACTION_SEARCH://按下搜索鍵
                        break;
                    default:
                        break;
                }
                return false;
            }
        });

除了設(shè)置搜索按鈕之外,還有很多選項(xiàng) actionGo,actionSend,actionNext等,具體的效果,可以自己試試看,道理都是一樣的。

EditText 輸入限制

inputType 設(shè)置輸入類型,例如只能輸入數(shù)字,或者輸入密碼

inputType 可以通過 xml 設(shè)置android:inputType屬性和代碼中 setInputType()
方法設(shè)置。
API提供了很多種現(xiàn)成的格式供我們選擇, 而且這些格式可以自由組合。

android:inputType="numberPassword|number"

以上設(shè)置支持密文輸入,并且限制只允許輸入數(shù)字

digits 設(shè)置具體的支持字符

這個(gè)屬性也支持通過代碼和布局屬性設(shè)置,和 inputType 的不同之處在于,可以說這個(gè)屬性可以自定義具體的支持字符。

例如設(shè)置 EditText 只能輸入字符和數(shù)字:

android:digits="0123456789abcdefghijklmnopqrstuvwxyz"

設(shè)置 TextWather 監(jiān)測輸入內(nèi)容

TextWather 監(jiān)聽EditText的字符變化, 拿到用戶的輸入內(nèi)容,做我們想要的處理。這個(gè)處理可以分為兩類:

  1. 作為一個(gè)輸入限制使用。實(shí)現(xiàn) inputType 和 digits 兩個(gè)屬性無法實(shí)現(xiàn)的特殊的輸入限制需求,例如限制只輸入小數(shù)點(diǎn)后兩位 。
  2. 作為一個(gè)事件監(jiān)聽使用。滿足某種情況,觸發(fā)相應(yīng)的邏輯,例如當(dāng)輸入 16 位身份證號碼時(shí)自動調(diào)用接口驗(yàn)證是否真實(shí)有效。

這里給出一個(gè)限制只輸入小數(shù)點(diǎn)后兩位的例子。


//限制的位數(shù)
int digits = 2;

mEditText.addTextChangedListener(new TextWatcher() {
           @Override
           public void beforeTextChanged(CharSequence s, int start, int count, int after) {

           }

           @Override
           public void onTextChanged(CharSequence s, int start, int before, int count) {
             //刪除“.”后面超過2位后的數(shù)據(jù)
                    if (s.toString().contains(".")) {
                        if (s.length() - 1 - s.toString().indexOf(".") > digits) {
                            s = s.toString().subSequence(0,
                                    s.toString().indexOf(".") + digits+1);
                            editText.setText(s);
                            editText.setSelection(s.length()); //光標(biāo)移到最后
                        }
                    }
                    //如果"."在起始位置,則起始位置自動補(bǔ)0
                    if (s.toString().trim().substring(0).equals(".")) {
                        s = "0" + s;
                        editText.setText(s);
                        editText.setSelection(2);
                    }

                    //如果起始位置為0,且第二位跟的不是".",則無法后續(xù)輸入
                    if (s.toString().startsWith("0")
                            && s.toString().trim().length() > 1) {
                        if (!s.toString().substring(1, 2).equals(".")) {
                            editText.setText(s.subSequence(0, 1));
                            editText.setSelection(1);
                            return;
                        }
                    }
           }

           @Override
           public void afterTextChanged(Editable s) {

           }
       });

設(shè)置 InputFilter 過濾器

除了 TextWather,自定義 InputFilter 過濾器也能達(dá)到我們特殊的過濾需求。例如上面的限制兩位小數(shù)點(diǎn)后兩位。

設(shè)置 InputFilter 過濾器需要兩步:

  1. 自定義 InputFilter, 繼承一個(gè)合適的 KeyListener, 重寫filter()方法,這里面編寫你想要的過濾限制。
  2. EditText 通過 setFilters 設(shè)置過濾器。

在我看來,如果實(shí)現(xiàn)輸入限制這類功能,InputFilter 的實(shí)現(xiàn)方式比 TextWather 顯的更加優(yōu)雅一點(diǎn),而且從方法名稱上看也是理所當(dāng)然的。TextWather 更適合去做監(jiān)聽類使用。

下面給出限制兩位小數(shù)點(diǎn)后兩位的 InputFilter 實(shí)現(xiàn)版本。

public class MoneyValueFilter extends DigitsKeyListener {

    private static final String TAG = "MoneyValueFilter";
    public MoneyValueFilter() {
        super(false, true);
    }

    private int digits = 2;

    public MoneyValueFilter setDigits(int d) {
        digits = d;
        return this;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end,
                               Spanned dest, int dstart, int dend) {
        CharSequence out = super.filter(source, start, end, dest, dstart, dend);


        // if changed, replace the source
        if (out != null) {
            source = out;
            start = 0;
            end = out.length();
        }

        int len = end - start;

        // if deleting, source is empty
        // and deleting can't break anything
        if (len == 0) {
            return source;
        }

        //以點(diǎn)開始的時(shí)候,自動在前面添加0
        if(source.toString().equals(".") && dstart == 0){
            return "0.";
        }
        //如果起始位置為0,且第二位跟的不是".",則無法后續(xù)輸入
        if(!source.toString().equals(".") && dest.toString().equals("0")){
            return "";
        }

        int dlen = dest.length();

        // Find the position of the decimal .
        for (int i = 0; i < dstart; i++) {
            if (dest.charAt(i) == '.') {
                // being here means, that a number has
                // been inserted after the dot
                // check if the amount of digits is right
                return (dlen-(i+1) + len > digits) ?
                    "" :
                    new SpannableStringBuilder(source, start, end);
            }
        }

        for (int i = start; i < end; ++i) {
            if (source.charAt(i) == '.') {
                // being here means, dot has been inserted
                // check if the amount of digits is right
                if ((dlen-dend) + (end-(i + 1)) > digits)
                    return "";
                else
                    break;  // return new SpannableStringBuilder(source, start, end);
            }
        }



        // if the dot is after the inserted part,
        // nothing can break
        return new SpannableStringBuilder(source, start, end);
    }
}


mEditText.setFilters(new InputFilter[]{new MoneyValueFilter().setDigits(3)});

最后

雖然都是一些小細(xì)節(jié),也要重視起來,因?yàn)榧?xì)節(jié)決定成敗吶,希望自己以后要多注意,努力降低 bug 率,F(xiàn)ighting!

另外,關(guān)于限制兩位小樹輸入的需求的代碼已上傳我的 github,項(xiàng)目地址為 DR_MoneyEditTextDemo,歡迎 Star,熱烈歡迎 Follow 。


歡迎關(guān)注博主的微信公眾號,快快加入哦,期待與你一起成長!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,030評論 25 709
  • 引言 EditTex是Android中比較常用的一個(gè)控件,可以說它是用戶和Android應(yīng)用進(jìn)行數(shù)據(jù)傳遞的通道.通...
    OzanShareing閱讀 6,624評論 5 33
  • 目 錄|河伯與共工 上一章|長生館(6)黃泉的真像 扶風(fēng)城北近郊有一小鎮(zhèn)平安,鎮(zhèn)上有間客棧名為長生館。菜品新奇,食...
    寧采野花不采臣閱讀 1,384評論 18 21
  • 為什么活著? 想了許久仍在原點(diǎn) 或許沒什么好想的 春冬秋夏 四季輪回 人也在這世上走了一遭 本就無奇 你不想只是為...
    胡蘿卜拐跑了小兔子閱讀 227評論 1 0

友情鏈接更多精彩內(nèi)容