1. 程式人生 > >Android 軟鍵盤事件imeOptions響應

Android 軟鍵盤事件imeOptions響應

在android發開過程中,有時候需要對EditText的軟鍵盤進行監聽。
當點選軟鍵盤迴車位置按鍵的時候,需要實現 完成、前進、下一項、搜尋、傳送或其他功能,這就需要開發者對軟鍵盤迴車的點選事件進行捕捉。
比如在登入介面,需要使用者在輸入密碼之後點選軟鍵盤迴車直接登入,不必再去點選螢幕上的登入按鈕。我們就可以在密碼使用的EditText設定 android:imeOptions=”actionDone”,然後對EditText設定OnEditorActionListener監聽,當捕捉到使用者點選完成時,呼叫登入方法即可。(IME英文全稱Input Method Editors,中文名稱輸入法編輯器

先看一個demo
佈局檔案如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight
="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context=".MainActivity">
<ScrollView android:layout_width="fill_parent" android:layout_height
="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <EditText android:id="@+id/actionDoneEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionDone" android:hint="actionDone" /> <EditText android:id="@+id/actionGoEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionGo" android:hint="actionGo" /> <EditText android:id="@+id/actionNextEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionNext" android:hint="actionNext" /> <EditText android:id="@+id/actionNoneEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionNone" android:hint="actionNone" /> <EditText android:id="@+id/actionPreviousEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionPrevious" android:hint="actionPrevious" /> <EditText android:id="@+id/actionSearchEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionSearch" android:hint="actionSearch" /> <EditText android:id="@+id/actionUnspecifiedEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionUnspecified" android:hint="actionUnspecified" /> <EditText android:id="@+id/actionSendEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:inputType="text" android:imeOptions="actionSend" android:hint="actionSend" /> </LinearLayout> </ScrollView> </LinearLayout>

Attention One:
使用android:imeOptions屬性的時候,一定要對EditText設定 android:inputType 或者 設定 android:singleline=”true”。

在activity_main.xml檔案中,定義了8個EditText,imeOptions分別是:
actionDone 完成 對應 EditorInfo.IME_ACTION_DONE
actionGo 前進 對應 EditorInfo.IME_ACTION_GO
actionNext 下一項 對應 EditorInfo.IME_ACTION_NEXT
actionNone 無動作 對應 EditorInfo.IME_ACTION_NONE
actionPrevious 上一項 對應 EditorInfo.IME_ACTION_PREVIOUS
actionSearch 搜尋 對應 EditorInfo.IME_ACTION_SEARCH
actionUnspecified 未指定 對應 EditorInfo.IME_ACTION_UNSPECIFIED
actionSend 傳送 對應 EditorInfo.IME_ACTION_SEND

在MainActivity中:

public class MainActivity extends Activity implements TextView.OnEditorActionListener {

    private EditText mActionDoneEditText;
    private EditText mActionGoEditText;
    private EditText mActionNextEditText;
    private EditText mActionNoneEditText;
    private EditText mActionPreviousEditText;
    private EditText mActionSearchEditText;
    private EditText mActionSendEditText;
    private EditText mActionUnspecifiedEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mActionDoneEditText = (EditText) findViewById(R.id.actionDoneEditText);
        mActionGoEditText = (EditText) findViewById(R.id.actionGoEditText);
        mActionNextEditText = (EditText) findViewById(R.id.actionNextEditText);
        mActionNoneEditText = (EditText) findViewById(R.id.actionNoneEditText);
        mActionPreviousEditText = (EditText) findViewById(R.id.actionPreviousEditText);
        mActionSearchEditText = (EditText) findViewById(R.id.actionSearchEditText);
        mActionSendEditText = (EditText) findViewById(R.id.actionSendEditText);
        mActionUnspecifiedEditText = (EditText) findViewById(R.id.actionUnspecifiedEditText);

        mActionDoneEditText.setOnEditorActionListener(this);
        mActionGoEditText.setOnEditorActionListener(this);
        mActionNextEditText.setOnEditorActionListener(this);
        mActionNoneEditText.setOnEditorActionListener(this);
        mActionPreviousEditText.setOnEditorActionListener(this);
        mActionSearchEditText.setOnEditorActionListener(this);
        mActionSendEditText.setOnEditorActionListener(this);
        mActionUnspecifiedEditText.setOnEditorActionListener(this);
    }

    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        doWhichOperation(actionId);
        Log.e("BALLACK", "event: " + event);
        Log.e("BALLACK", "v.getImeActionId(): " + v.getImeActionId());
        Log.e("BALLACK", "v.getImeOptions(): " + v.getImeOptions());
        Log.e("BALLACK", "----------------------------------------------");
        return true;
    }

    private void doWhichOperation(int actionId) {
        switch (actionId) {
            case EditorInfo.IME_ACTION_DONE:
                Log.e("BALLACK", "IME_ACTION_DONE");
                break;
            case EditorInfo.IME_ACTION_GO:
                Log.e("BALLACK", "IME_ACTION_GO");
                break;
            case EditorInfo.IME_ACTION_NEXT:
                Log.e("BALLACK", "IME_ACTION_NEXT");
                break;
            case EditorInfo.IME_ACTION_NONE:
                Log.e("BALLACK", "IME_ACTION_NONE");
                break;
            case EditorInfo.IME_ACTION_PREVIOUS:
                Log.e("BALLACK", "IME_ACTION_PREVIOUS");
                break;
            case EditorInfo.IME_ACTION_SEARCH:
                Log.e("BALLACK", "IME_ACTION_SEARCH");
                break;
            case EditorInfo.IME_ACTION_SEND:
                Log.e("BALLACK", "IME_ACTION_SEND");
                break;
            case EditorInfo.IME_ACTION_UNSPECIFIED:
                Log.e("BALLACK", "IME_ACTION_UNSPECIFIED");
                break;
            default:
                break;
        }
    }

}

在 onEditorAction方法中先通過doWhichOperation(actionId)判斷點選的是什麼操作,然後列印相關操作資訊

        Log.e("BALLACK", "event: " + event);
        Log.e("BALLACK", "v.getImeActionId(): " + v.getImeActionId());
        Log.e("BALLACK", "v.getImeOptions(): " + v.getImeOptions());
        Log.e("BALLACK", "----------------------------------------------");

Android原始碼中,對EditorInfo定義了常用的IME常量值:

public static final int IME_ACTION_UNSPECIFIED = 0x00000000;
public static final int IME_ACTION_NONE = 0x00000001;
public static final int IME_ACTION_GO = 0x00000002;
public static final int IME_ACTION_SEARCH = 0x00000003;
public static final int IME_ACTION_SEND = 0x00000004;
public static final int IME_ACTION_NEXT = 0x00000005;
public static final int IME_ACTION_DONE = 0x00000006;
public static final int IME_ACTION_PREVIOUS = 0x00000007;

下面是設定不同android:imeOptions時軟鍵盤迴車鍵顯示的不同效果和點選之後系統的列印資訊
1. android:imeOptions=”actionDone”
這裡寫圖片描述
圖片右下角顯示”完成
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_DONE,v.getImeOptions()=6
actionId和 EditorInfo.IME_ACTION_DONE 可以一一對應。
2. android:imeOptions=”actionGo”
這裡寫圖片描述
圖片右下角顯示”前往
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_GO,v.getImeOptions()=2
actionId和 EditorInfo.IME_ACTION_GO可以一一對應。
3. android:imeOptions=”actionNext”
這裡寫圖片描述
圖片右下角顯示”下一項
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_NEXT,v.getImeOptions()=5
actionId和 EditorInfo.IME_ACTION_NEXT可以一一對應。
4. android:imeOptions=”actionPrevious”
這裡寫圖片描述
圖片右下角顯示”上一項
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_PREVIOUS,v.getImeOptions()=7,actionId和 EditorInfo.IME_ACTION_PREVIOUS可以一一對應。
5. android:imeOptions=”actionSearch”
這裡寫圖片描述
圖片右下角顯示”搜尋
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_SEARCH,v.getImeOptions()=3,actionId和 EditorInfo.IME_ACTION_SEARCH可以一一對應。
6. android:imeOptions=”actionSend”
這裡寫圖片描述
圖片右下角顯示”傳送
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_SEND,v.getImeOptions()=4,actionId和 EditorInfo.IME_ACTION_SEND可以一一對應。
7. android:imeOptions=”actionUnspecified”
這裡寫圖片描述
圖片右下角顯示”下一項
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_NEXT,v.getImeOptions()=0,actionId和 EditorInfo.IME_ACTION_UNSPECIFIED無法對應上。
8. android:imeOptions=”actionNone”
這裡寫圖片描述
圖片右下角顯示”回車
這裡寫圖片描述
在Log資訊中,可以看到,通過actionId匹配到EditorInfo.IME_ACTION_UNSPECIFIED,v.getImeOptions()=1,actionId和 EditorInfo.IME_ACTION_NONE無法對應上,而且出現兩次重複的Log資訊。

在上述出現的8個不同效果上android:imeOptions=”actionUnspecified”和android:imeOptions=”actionNone”出現了錯誤的資訊,無法和EditorInfo中的值對應上,v.getImeOptions()取得的值和EditorInfo中的常量可以一一對應。

Attention Two:
actionId是系統捕捉到使用者點選鍵盤時取得的數值,而v.getImeOptions()拿到的是在xml檔案中對EditText設定的android:imeOptions屬性的數值,這就是為什麼v.getImeOptions()和EditorInfo永遠可以一一對應的原因。

在原始碼中,對IME_ACTION_UNSPECIFIED定義是:

 /**
   * Bits of {@link #IME_MASK_ACTION}: no specific action has been
   * associated with this editor, let the editor come up with its own if
   * it can.
   */
public static final int IME_ACTION_UNSPECIFIED = 0x00000000;

沒有特別指定要進行什麼動作,由編輯器自己指定,當EditText處於不同的位置的時候,系統自動判斷當前EditText可能需要執行什麼樣的動作。當把指定為actionUnspecified的EditText放在最後面的時候,就會顯示為”完成“,打印出來的資訊也會是 IME_ACTION_DONE。

同理,IME_ACTION_NONE也是這樣:

/**
  * Bits of {@link #IME_MASK_ACTION}: there is no available action.
  */
public static final int IME_ACTION_NONE = 0x00000001;

指定為actionDone的EditText沒有指定任何動作,就會被系統預設顯示回車。

在TextView的原始碼中,對介面OnEditoractionListener的定義如下:

/**
  * Interface definition for a callback to be invoked when an action is
  * performed on the editor.
  */
    public interface OnEditorActionListener {
        /**
         * Called when an action is being performed.
         *
         * @param v The view that was clicked.
         * @param actionId Identifier of the action.  This will be either the
         * identifier you supplied, or {@link EditorInfo#IME_NULL
         * EditorInfo.IME_NULL} if being called due to the enter key
         * being pressed.
         * @param event If triggered by an enter key, this is the event;
         * otherwise, this is null.
         * @return Return true if you have consumed the action, else false.
         */
        boolean onEditorAction(TextView v, int actionId, KeyEvent event);
    }

如果actionId 沒有特別指定的話,就會被預設為IME_NULL,再檢視EditorInfo原始碼發現:

/**
 * Generic unspecified type for {@link #imeOptions}.
 */
public static final int IME_NULL = 0x00000000;

在EditorInfo中,有兩個常量IME_NULL和IME_ACTION_UNSPECIFIED的值都是0x00000000。
android:imeOptions=”actionNone”打印出來的資訊出現IME_ACTION_UNSPECIFIED,其實由於沒有任何動作,應該是IME_NULL,只是在MainActivity程式碼中對actionId=0時統一指定為了IME_ACTION_UNSPECIFIED。

Attention Three:
部分第三方的輸入法,對EditorInfo支援的不一樣,有的功能實現了,但是對應的圖示沒有修改過來,有的乾脆功能就沒有實現。比如谷歌自己的輸入法,就不支援actionPrevious的圖示和功能,而百度輸入法的小米專用版中,actionPrevious功能雖然實現了,但是圖示仍然顯示的是回車的圖示。

對EditText指定不同的imeOptions之後,就需要實現OnEditorActionListener 中的onEditorAction()方法,然後根據不同的動作執行進行響應。
對於actionDone、actionNext和actionPrevious,系統都自己進行了部分處理。
- actionDone:隱藏輸入法
- actionNext:跳到下一個EditText
- actionPrevious:跳到上一個EditText

然並卵!!!
原因在於,在TextView原始碼的方法onEditorAction()中:

public void onEditorAction(int actionCode) {
        final Editor.InputContentType ict = mEditor == null ? null : mEditor.mInputContentType;
        if (ict != null) {
            if (ict.onEditorActionListener != null) {
                if (ict.onEditorActionListener.onEditorAction(this,
                        actionCode, null)) {
                    return;
                }
            }

            // This is the handling for some default action.
            // Note that for backwards compatibility we don't do this
            // default handling if explicit ime options have not been given,
            // instead turning this into the normal enter key codes that an
            // app may be expecting.
            if (actionCode == EditorInfo.IME_ACTION_NEXT) {
                View v = focusSearch(FOCUS_FORWARD);
                if (v != null) {
                    if (!v.requestFocus(FOCUS_FORWARD)) {
                        throw new IllegalStateException("focus search returned a view " +
                                "that wasn't able to take focus!");
                    }
                }
                return;

            } else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
                View v = focusSearch(FOCUS_BACKWARD);
                if (v != null) {
                    if (!v.requestFocus(FOCUS_BACKWARD)) {
                        throw new IllegalStateException("focus search returned a view " +
                                "that wasn't able to take focus!");
                    }
                }
                return;

            } else if (actionCode == EditorInfo.IME_ACTION_DONE) {
                InputMethodManager imm = InputMethodManager.peekInstance();
                if (imm != null && imm.isActive(this)) {
                    imm.hideSoftInputFromWindow(getWindowToken(), 0);
                }
                return;
            }
        }

        ViewRootImpl viewRootImpl = getViewRootImpl();
        if (viewRootImpl != null) {
            long eventTime = SystemClock.uptimeMillis();
            viewRootImpl.dispatchKeyFromIme(
                    new KeyEvent(eventTime, eventTime,
                    KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                    KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
                    | KeyEvent.FLAG_EDITOR_ACTION));
            viewRootImpl.dispatchKeyFromIme(
                    new KeyEvent(SystemClock.uptimeMillis(), eventTime,
                    KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                    KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
                    | KeyEvent.FLAG_EDITOR_ACTION));
        }
    }

系統會首先判斷使用者實現的方法ict.onEditorActionListener.onEditorAction(this, actionCode, null)的返回值,一旦返回true,會立即return,因此係統的處理被直接跳過。
如果想自己實現部分功能,然後其他的基本操作由系統完成,那就在實現方法onEditorAction()是返回false。

相關推薦

Android 鍵盤事件imeOptions響應

在android發開過程中,有時候需要對EditText的軟鍵盤進行監聽。 當點選軟鍵盤迴車位置按鍵的時候,需要實現 完成、前進、下一項、搜尋、傳送或其他功能,這就需要開發者對軟鍵盤迴車的點選事件進行捕捉。 比如在登入介面,需要使用者在輸入密碼之後點選軟鍵盤

android鍵盤事件響應android EditText inputType 及 android:imeOptions=”actionDone”

inputKey = (EditText) findViewById(R.id.contactSearch_editText); inputKey.addTextChangedListener(watcher); inputKey.setOnKeyListener(new View.OnKeyListene

Android 鍵盤imeOptions(Done)的用法

正文 android:imeOptions="flagNoExtractUi" //使軟鍵盤不全屏顯示,只佔用一部分螢幕 同時,這個屬性還能控制元件軟鍵盤右下角按鍵的顯示內容,預設情況下為

Android 鍵盤監聽事件

   Android軟鍵盤的隱藏顯示研究 Android是一個針對觸控式螢幕專門設計的作業系統,當點選編輯框,系統自動為使用者彈出軟鍵盤,以便使用者進行輸入。     那麼,彈出軟鍵盤後必然會造成原有佈局高度的減少,那麼系統應該如何來處理佈局的減少?我們能否在應用程式中進行

Android鍵盤狀態的切換及其強制隱藏

padding protected systems -m ride apk undle inb new MainActivity例如以下: package cc.c; import android.os.Bundle; import android.view.View

求助aNDROID鍵盤問題

軟鍵盤 hao123 com baidu 鍵盤 5% list ongl oid %E6%80%A5%E6%B1%82%7E%7E%E5%AF%B9%E5%A4%A7%E5%9B%BE%E7%89%87%E8%BF%9B%E8%A1%8C%E8%B0%83%E8%89%B2

移動端Android鍵盤遮住輸入框解決!

res set pan area app tar span lac row 在使用vue的情況下,在輸入框中添加 <textarea class="textarea" @click="isAndroid" :maxlength="30" :rows="1" plac

Android 鍵盤的顯示和隱藏,這樣操作就對了

ide min 影響 想要 manage 總結 ice 技術 3.1 一、前言 如果有需要用到輸入的地方,通常會有需要自動彈出或者收起軟鍵盤的需求。開篇明義,本文會講講彈出和收起軟鍵盤的一些細節,最終還會從源碼進行分析。 想要操作軟鍵盤,需要使用到 InputMethod

Android鍵盤彈出,覆蓋h5頁面輸入框問題

問題 過多 繼承 col 鍵盤 代碼 chrom 技術 fff 之前我們在使用vue進行 h5 表單錄入的過程中,遇到了Android軟鍵盤彈出,覆蓋 h5頁面 輸入框 問題,在此進行回顧並分享給大家: 系統:Android 條件:當輸入框在可視區底部或者偏下的位置 觸發

Android鍵盤監聽KeyboardWatcher

轉載請標明出處:http://blog.csdn.net/wu_wxc/article/details/53705322 本文出自【吳孝城的CSDN部落格】 在如登入介面上當輸入框獲得焦點時,為了將輸入框顯示出來,不被軟鍵盤遮住,我們可以監聽軟鍵盤的顯示與關閉來實現

關於Android鍵盤遮擋的問題

在開發登入介面時,點選某個EditText準備輸入,彈出的軟鍵盤遮擋了按鈕或者下面的輸入框,在完成這個文字框的輸入後,想要繼續下面的操作,需要先隱藏軟鍵盤。這會影響使用者操作的流暢感,所以需要解決。 問題如下: image.png 解決方法 監聽佈局變化,當軟鍵盤彈出時,滾

android 鍵盤彈出 佈局上移動

這是軟體盤和actiivty主視窗搶空間造成的,需在AndroidManifest.xml裡為activity配置windowSoftInputMode屬性併為其選擇屬性值。 如下: <activity android:name="...Activity" a

Android鍵盤彈出,介面整體上移終極解決方式

今天在應測試要求:軟鍵盤彈出不能遮擋EditView,在網上找了各種方案,基本都不行,比如: android:windowSoftInputMode=“adjustResize|stateHidden” 可能在一般的頁面是可以用吧。 下面來說一個曲線救國的方案,

Android 鍵盤踩坑記

最近在開發一個朋友圈產品的時候遇到一個bug:軟鍵盤遮罩,在解決的過程中我通過百度、谷歌查找了好半天,最終經歷了一番坎坷才解決,具體過程且聽我娓娓道來! 一、windowSoftInputMode 這個是在遇到軟鍵盤相關的問題,腦子裡第一個想到的知識點,但是效果如何呢?能解決問題,但是不完美! 先看沒有解

Android鍵盤的隱藏顯示研究

原文地址 http://winuxxan.blog.51cto.com/2779763/522810   Android是一個針對觸控式螢幕專門設計的作業系統,當點選編輯框,系統自動為使用者彈出軟鍵盤,以便使用者進行輸入。     那麼,彈出軟鍵盤後必然會造成原有佈局

Android鍵盤遮擋的四種解決方案

問題概述 在編輯框輸入內容時會彈出軟鍵盤,而手機螢幕區域有限往往會遮住輸入介面,我們先看一下問題效果圖: 輸入使用者名稱和密碼時,系統會彈出鍵盤,造成系統鍵盤會擋住文字框的問題,如圖所示: 輸入密碼時輸入框被系統鍵盤遮擋了,大大降低了使用者操作體驗,這就是開發中非常常見的軟鍵盤遮擋的問題,

android 鍵盤管理

package com.dejun.commonsdk.util; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.gr

Android 鍵盤按鍵監控

最近在做專案,遇到一個比較頭疼的問題,問題是需要對使用者的輸入進行時時監聽,而大部分使用者的輸入是通過軟鍵盤來完成的,而Android平臺好象沒有專門的對此監控事件,那該怎麼辦呢? 最終解決辦法就是通過EditText和TextWatcher類來輔助監聽。具體做法如下

Android 鍵盤原理 鍵盤彈出時與介面的互動

本文轉載於http://hkp.iteye.com/blog/1205492、http://blog.sina.com.cn/s/blog_6a156a1b0101547k.html,講述Android軟鍵盤原理,及彈出時與介面的互動方式。軟鍵盤的本質是什麼?軟鍵盤其實是一個

android鍵盤右下角按鍵設定

預設情況,鍵盤右下角為Enter鍵。EditText提供了android:imeOptions屬性,控制該文字顯示。1、android:imeOptions="actionSearch" 文字為搜尋2、android:imeOptions="actionGo" 文字為開始3