天天看點

EditText軟鍵盤的顯示隐藏及焦點問題

簡介

EditText作為Android輸入框,對于Android開發來說,是不能再熟悉的一個控件。但是,使用EditText 有很多的細節需要注意。比如它的一些常用屬性、焦點問題、軟鍵盤的顯示隐藏等。在此,我做一些筆記,友善自己使用和記憶。

EditText 基本知識

示例代碼:

<EditText
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:gravity="center_vertical"
    android:paddingLeft="12dp"
    android:paddingRight="12dp"
    android:background="#ffffff"
    android:hint="請輸入"
    android:textSize="14px"
    android:inputType="text"
    android:maxLines="1"
    android:maxLength="20"
    android:textColor="#333333"
    android:textColorHint="#999999"
    />
           

常用屬性及作用

  • hint 和 tools:text

hint 屬性主要用于設定提示文字,顔色可以通過屬性

textColorHint

設定,如:

android:textColorHint="#999999"

即設定提示文字顔色為#999999(淺灰色)。

tools:text 屬性用于開發時顯示文字,需要命名空間

xmlns:tools="http://schemas.android.com/tools"

與android:text 不同,它隻在開發工具的預覽(Preview)中可見,用于輔助開發。

類似的還有

tools:visibility="visible"

當我們設定

android:visibility="gone"

後,再加上這句代碼,就可以在預覽中顯示,實際中不顯示,以友善開發。tools 當然還有很多其他屬性,可以自己去發現。
  • maxLines、minLines、lines、maxLength、ems

maxLines:最大顯示行數,當EditText設定高度為wrap_content,即

android:layout_height="wrap_content"

後,設定最大顯示行數,可以起到限制高度的效果。即高度随内容的行數增加,直到行數為maxLines高度不再增加。

minLines:最小顯示行數。當内容行數小于minLines時,EditText高度為minLines行高度,大于minLines行時,高度自适應。

lines:顯示行數,用于限制EditText行數,當EditText設定高度為wrap_content,EditText會顯示行數為 lines時的高度,不管内容有多少。

maxLength:最大長度,限制内容長度,最大為maxLength。比較常用。

ems:目前字型下,最多可編輯多少個M字母寬度。設定為10時,最多編輯 10個em ,一個em機關是 兩個inch ,但是随着自動調整,在Android中 em代表‘M’的數量 。可以設定屬性

maxEms

minEms

  • inputType

輸入類型,EditText接受的輸入類型,可以控制軟鍵盤的輸入類型。

android:inputType="none"//輸入普通字元
    android:inputType="text"//輸入普通字元
    android:inputType="textCapCharacters"//輸入普通字元
    android:inputType="textCapWords"//單詞首字母大小
    android:inputType="textCapSentences"//僅第一個字母大小
    android:inputType="textAutoCorrect"//前兩個自動完成
    android:inputType="textAutoComplete"//前兩個自動完成
    android:inputType="textMultiLine"//多行輸入
    android:inputType="textImeMultiLine"//輸入法多行(不一定支援)
    android:inputType="textNoSuggestions"//不提示
    android:inputType="textUri"//URI格式
    android:inputType="textEmailAddress"//電子郵件位址格式
    android:inputType="textEmailSubject"//郵件主題格式
    android:inputType="textShortMessage"//短消息格式
    android:inputType="textLongMessage"//長消息格式
    android:inputType="textPersonName"//人名格式
    android:inputType="textPostalAddress"//郵政格式
    android:inputType="textPassword"//密碼格式
    android:inputType="textVisiblePassword"//密碼可見格式
    android:inputType="textWebEditText"//作為網頁表單的文本格式
    android:inputType="textFilter"//文本篩選格式
    android:inputType="textPhonetic"//拼音輸入格式
 
 
    //數值類型
    android:inputType="number"//數字格式
    android:inputType="numberSigned"//有符号數字格式
    android:inputType="numberDecimal"//可以帶小數點的浮點格式
    android:inputType="phone"//撥号鍵盤
    android:inputType="datetime"//日期+時間格式
    android:inputType="date"//日期鍵盤
    android:inputType="time"//時間鍵盤
           
參考:https://blog.csdn.net/zhangphil/article/details/79970667
  • imeOptions

根據輸入框輸入完成後要執行的業務邏輯指定軟鍵盤右下角Action按鈕的樣式和行為,如讓右下角按鈕顯示為“搜尋”,點選後執行搜尋邏輯。

imeOptions 有下面一些值:

imeOptions 屬性值 對應字段(EditorInfo.) 描述
actionDone IME_ACTION_DONE 完成
actionGo IME_ACTION_GO 前進
actionNext IME_ACTION_NEXT 下一項
actionPrevious IME_ACTION_PREVIOUS 上一項
actionSearch IME_ACTION_SEARCH 搜尋
actionNone IME_ACTION_NONE 無動作
actionUnspecified IME_ACTION_UNSPECIFIED 未指定
actionSend IME_ACTION_SEND 發送
flagForceAscii IME_FLAG_FORCE_ASCII 請求IME輸入法接受ASCII字元的輸入。
flagNoFullscreen IME_FLAG_NO_FULLSCREEN 請求IME輸入法永遠不要進入全屏模式。
flagNavigateNext IME_FLAG_NAVIGATE_NEXT 表明這裡有前進導航可以關注的興趣點,類似`IME_ACTION_NEXT`,不過允許IME輸入多行且提供前進導航。
flagNavigatePrevious IME_FLAG_NAVIGATE_PREVIOUS 類似IME_FLAG_NAVIGATE_NEXT, 表明這裡有後退導航可以關注的興趣點。
flagNoAccessoryAction IME_FLAG_NO_ACCESSORY_ACTION 和一個Action結合使用表明在全屏輸入法中不作為可通路性按鈕。
flagNoEnterAction IME_FLAG_NO_ENTER_ACTION 多行文本将自動設定了該标志位,執行Action時為換行效果,如果未設定,IME輸入法将把Enter按鈕自動替換為Action按鈕。
flagNoExtractUi IME_FLAG_NO_EXTRACT_UI 請求IME輸入法不要顯示額外的文本UI。

java代碼:

監聽:

mEt.setOnEditorActionListener(new OnEditorActionListener() {  
            @Override  
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {  
               if (actionId == EditorInfo.IME_ACTION_DONE) {
               // 按下完成按鈕,這裡和上面imeOptions對應
                text.setText("Editing EditorInfo.IME_ACTION_DONE");  
                return false;   //傳回true,保留軟鍵盤。false,隐藏軟鍵盤
                }
            }  
        });  
           

參考:https://blog.csdn.net/honjane/article/details/78699002

  • cursorVisible 和 textCursorDrawable

cursorVisible

:光标是否可見。

textCursorDrawable

:設定光标的樣式。

通過shape可以設定光标樣式:

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

加上padding可以處理末尾光标顯示不全問題:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <size android:width="1.2dp" />
    <solid android:color="#1b9fff" />
    <padding android:left="1.2dp" android:right="1.2dp" />
</shape>
           
  • selectAllOnFocus

android:selectAllOnFocus="true"

:當得到焦點時選擇全部。

軟體盤的視窗輸入模式和顯示隐藏

  • 視窗輸入模式

在清單檔案中,可通過設定屬性

android:windowSoftInputMode

(視窗輸入模式),控制軟鍵盤的可見性和軟鍵盤顯示時視窗的調整。例如:

<activity
    android:name=".AaActivity"
    android:windowSoftInputMode="stateVisible|adjustPan"
    android:screenOrientation="portrait" />
           

上面是 AndroidManifest.xml 檔案中的設定,代碼設定需要使用Activity的方法

getWindow().setSoftInputMode(int)

,如下:

下面是視窗軟鍵盤輸入模式的屬性值及其描述:

windowSoftInputMode 屬性值 對應字段(WindowManager.LayoutParams.) 描述
stateUnspecified SOFT_INPUT_STATE_UNSPECIFIED 可見性狀态:未指定。系統将選擇一個合适的狀态或依賴于主題的設定。
stateUnchanged SOFT_INPUT_STATE_UNCHANGED 可見性狀态:不更改輸入區(軟鍵盤)的狀态。當這個activity出現時,軟鍵盤将一直保持在上一個activity裡的狀态,無論是隐藏還是顯示。
stateVisible SOFT_INPUT_STATE_VISIBLE 可見性狀态:當定位到你的視窗時,顯示軟鍵盤。(如:進入AaActivity時,顯示軟鍵盤)
stateAlwaysVisible SOFT_INPUT_STATE_ALWAYS_VISIBLE 可見性狀态:目前視窗擷取輸入焦點時,始終顯示軟鍵盤。
stateHidden SOFT_INPUT_STATE_HIDDEN 可見性狀态:當定位到你的視窗時,隐藏軟鍵盤。(如:進入AaActivity時,隐藏軟鍵盤)
stateAlwaysHidden SOFT_INPUT_STATE_ALWAYS_HIDDEN 可見性狀态:目前視窗擷取焦點時,始終隐藏軟鍵盤。
adjustUnspecified SOFT_INPUT_ADJUST_UNSPECIFIED 調整選項:未指定。系統會根據視窗内容嘗試選擇adjustResize和adjustPan其中一個調整選項。
adjustResize SOFT_INPUT_ADJUST_RESIZE 調整選項:設定為允許在顯示輸入法時調整視窗的大小,以便輸入方法不覆寫其内容,即視窗大小調整。不能和SOFT_INPUT_ADJUST_PAN連用。這兩個都沒有設定,系統将根據視窗内容選擇其中一個。如果視窗的布局參數标志(layout parameter flags)包含FLAG_FULLSCREEN,這個将失效,視窗不會調整大小,但會保持全屏。
adjustPan SOFT_INPUT_ADJUST_PAN 調整選項:當顯示輸入方法時,設定為可以視窗平移,是以不需要調整大小處理,但隻需通過架構平移以確定目前輸入焦點可見,即視窗平移調整。目前視窗的内容将自動移動以便目前焦點從不被鍵盤覆寫和使用者能總是看到輸入内容的部分。不能和SOFT_INPUT_ADJUST_PAN連用。
adjustNothing SOFT_INPUT_ADJUST_NOTHING 調整選項:不因輸入法的顯示調整視窗,不會調整視窗大小,也不會被平移以使其焦點可見。
  • 輸入法顯示隐藏工具類

軟體盤的顯示隐藏,這裡提供一個工具類:

/**
 * 軟鍵盤工具類
 *   ·是否隐藏
 *   ·顯示
 *   ·隐藏
 */
public class SoftInputUtil {

    /**
     *  判斷鍵盤是否顯示(目前editText是否在輸入法活動狀态,即是否正在接收軟鍵盤輸入)。
     * @param editText 輸入框
     */
    public static boolean isSoftInputShowing(EditText editText){
        return isSoftInputShowing(editText.getContext(), editText);

    }

    /**
     * 判斷鍵盤是否顯示(目前view是否在輸入法活動狀态,即是否正在接收軟鍵盤輸入)。
     * @param context 上下文
     * @param view 目前聚焦的正在接收軟體盤輸入的View。
     */
    public static boolean isSoftInputShowing(Context context, View view) {
        boolean bool = false;
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null && imm.isActive(view)) {
            bool = true;
        }
        return bool;
    }

    /**
     * 判斷鍵盤是否顯示(是否有View是在輸入法活動狀态,即是否正有View正在接收軟鍵盤輸入)。
     * @param context 上下文
     */
    public static boolean isSoftInputShowing(Context context) {
        boolean bool = false;
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null && imm.isActive()) {
            bool = true;
        }
        return bool;
    }

    /**
     * 顯示鍵盤
     * @param view 目前聚焦的正在接收軟體盤輸入的View,通常為EditText。
     */
    public static void showSoftInput(View view) {
        showSoftInput(view.getContext(), view);
    }

    /**
     * 顯示鍵盤
     * @param context 上下文
     * @param view 目前聚焦的正在接收軟體盤輸入的View,通常為EditText。
     */
    public static void showSoftInput(Context context, View view) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            //第二個參數為flags, 0 | InputMethodManager.SHOW_FORCED | InputMethodManager.SHOW_IMPLICIT
            imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
        }
    }

    /**
     * 隐藏軟鍵盤
     * @param activity
     */
    public static void hideSoftInput(Activity activity) {
        View view = activity.getWindow().peekDecorView();
        if (view != null) {
            hideSoftInput(activity, view);
        }
    }

    public static void hideSoftInput(View view) {
        if (view != null) {
            hideSoftInput(view.getContext(), view);
        }
    }

    /**
     * 隐藏輸入法
     * @param context 上下文
     * @param view 可以是任意已添加到window中的View(已添加到布局中的View)。
     */
    public static void hideSoftInput(Context context, View view) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null && imm.isActive()) {
            //第二個參數為flags, 0 | InputMethodManager.HIDE_IMPLICIT_ONLY | InputMethodManager.HIDE_NOT_ALWAYS
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    }
    
}
           

EditText 焦點問題

有時候我們想要一進入界面(帶有輸入框)就顯示或隐藏輸入法(軟鍵盤)。除了通過設定上面介紹的視窗輸入模式,也可以通過EditText 擷取和失去焦點來影響軟鍵盤的顯示或隐藏。

如果沒有設定視窗的輸入模式,系統會根據視窗内容自動選擇一個合适的模式。

· 一進界面顯示輸入法

想要一進界面就把叫焦點和光标定位到某個輸入框,并顯示輸入法,可以設定屬性

focusable

focusableInTouchMode

true

,如下所示:

<EditText
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:gravity="center_vertical"
    android:paddingLeft="12dp"
    android:paddingRight="12dp"
    android:background="#ffffff"
    android:hint="請輸入"
    android:textSize="14px"
    android:inputType="text"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:textColor="#333333"
    android:textColorHint="#999999"
    />
           

· 一進界面隐藏輸入法

進入界面時不想讓輸入框獲得焦點,不顯示光标,不顯示輸入框,可以去掉上面的 EditText 的 focusable 和 focusableInTouchMode 屬性,給它的父容器或最外層容器或其他不相幹的View設定這兩個屬性為true,把焦點轉移出去。否則,系統會檢測焦點,當找不到其他可獲得焦點的View時,會檢測到輸入框把焦點交給它;當有多個輸入框的時候,焦點可能轉移到其他輸入框。

如果想在觸發點選事件時隐藏軟體盤并且使光标不可見,可使用如下代碼:

public void hideSoftInput(View root) {
        View v = root.findFocus();
        if (v != null && (v instanceof EditText)) {
            //使EditText觸發一次失去焦點事件
            v.setFocusable(false);
//                v.setFocusable(true); //這裡不需要是因為下面一句代碼會同時實作這個功能
            v.setFocusableInTouchMode(true);

        }
        SoftInputUtil.hideSoftInput(v);
    }
           

在點選監聽回調等合适的地方隐藏軟鍵盤。

注意:SoftInputUtil 是上面提供的工具類。參數root最好是目前頁所有輸入框共同的父容器。

在Activity中可以使用方法 getCurrentFocus(),擷取到目前得到焦點的View,上面代碼就可以是:

public void hideSoftInput() {
        View v = getCurrentFocus();
        if (v != null && (v instanceof EditText)) {
            //使EditText觸發一次失去焦點事件
            v.setFocusable(false);
//                v.setFocusable(true); //這裡不需要是因為下面一句代碼會同時實作這個功能
            v.setFocusableInTouchMode(true);

        }
        SoftInputUtil.hideSoftInput(v);
    }
           

如果想在輸入框外部點選都隐藏輸入框,可以參考 Android中EditText焦點問題:https://www.jianshu.com/p/3d31d681f4bc

參考:

[1] https://blog.csdn.net/a641324093/article/details/62238385

[2] https://blog.csdn.net/honjane/article/details/78699002

[3] https://www.jianshu.com/p/4e238eb1deb2

[4] https://blog.csdn.net/wei_zhi/article/details/50183605?utm_source=itdadao&utm_medium=referral

[5] Android中EditText焦點問題:https://www.jianshu.com/p/3d31d681f4bc