1. 程式人生 > >Android 攔截返回鍵事件

Android 攔截返回鍵事件

KeyEvent類

Android.View.KeyEvent類中定義了一系列的常量和方法,用來描述Android中的按鍵事件。
和返回鍵有關的常量和方法有。
KeyEvent.KEYCODE_BACK: 表示key型別為返回鍵
KeyEvent.ACTION_DOWN:表示事件為按下key,如果一直按住不放,則會不停產生此事件。
KeyEvent.ACTION_UP:表示事件為為放開key,一次點選key過程只會呼叫一次。
public final int getKeyCode():獲取此事件對應的key型別。
public final int getAction():獲取此事件對應的事件型別

Activity中攔截返回鍵

在Activity的派生類中可以通過重寫onKeyDown和onKeyUp這兩個方法來攔截返回鍵。這兩個方法的原型為。

public boolean onKeyDown(int keyCode, KeyEvent event);
public boolean onKeyUp(int keyCode, KeyEvent event);

這兩個方法都有兩個引數,第一個引數為keyCode,即此事件對應的key型別。第二個引數為此事件物件,
通過event可以獲取到事件的詳細資訊。onKeyDown()方法中event.getAction()返回的始終是KeyEvent.ACTION_DOWN,onKeyUp()方法中event.getAction()返回的始終是KeyEvent.ACTION_UP。
如果要攔截返回鍵,則在兩個方法中加入如下程式碼。

if (keyCode == KeyEvent.KEYCODE_BACK) {
    ...
}

Dialog中攔截返回鍵

在Dialog中可以通過呼叫setOnKeyListener()方法來為Dialog增加按鍵事件的監聽。
setOnKeyListener()方法原型為:

public void setOnKeyListener(final OnKeyListener onKeyListener);

此方法有一個引數,引數需要實現OnKeyListener介面。OnKeyListener介面定義如下。

interface OnKeyListener {
    public
boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event); }

onKey()方法包含三個引數,第一個引數是攔截到此事件的對話方塊物件的引用。第二個引數是此事件對應的keyCode,第三個引數是此事件物件本身。
如果要攔截返回鍵,則在Dialog中加入如下程式碼。

setOnKeyListener(new OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK 
            && event.getAction() == KeyEvent.ACTION_UP) {
            ...
        }
        return false;
    }
});

EditText中攔截返回鍵事件

在EditText中同樣可以通過呼叫setOnKeyListener()方法來為EditText增加按鍵事件的監聽。
setOnKeyListener()方法的使用和Dialog中完全相同。

View中攔截返回鍵事件

在所有View的派生類物件上都可以呼叫setOnKeyListener()方法來增加按鍵事件的監聽,不過除了EditText之外,其他View設定了監聽並不會起到作用。按鍵事件產生時並不會分發到View上。

多個攔截事件的衝突與選擇

目前在Activity,Dialog和EditText中都可以成功設定攔截事件。如果多個物件設定了攔截事件。則事件只會分發到一個物件上。
通過實驗得到如下結論:
1、Dialog優先順序最高,如果有一個Activity,Activity中彈出一個Dialog,Dialog中有一個EditText,在Activity,Dialog和EditText中都設定監聽,只有Dialog中設定的監聽過程能夠正確執行。Activity和EditText中的監聽過程無法被執行到。
2、Activity優先順序次於Dialog,但高於EditText,如果有一個Activity,Activity中有一個EditText,在Activity和EditText中都設定監聽,只有Activity中設定的監聽過程能夠正確執行。EditText中的監聽過程無法被執行到。
3、如果當前介面中有PopupWindow,則按返回鍵後PopupWindow會收到事件通知,並消費(執行dismiss();)。其他設定了監聽的物件無法獲取到事件通知。(原因是PopupWindow內部佈局類PopupViewContainer重寫了dispatchKeyEvent()方法)

返回鍵響應速度限制

當用戶在按返回鍵後,如果介面出現卡頓,導致介面沒有立刻完成返回動作,這時使用者可能覺得是按下操作沒有成功,又再一次按下返回鍵。這會導致返回事件又一次被呼叫。當卡頓結束後就出現多次返回的現象。為了避免這種情況出現,可以在攔截返回鍵的函式中增加時間限制。即如果本次返回事件距離上次處理時間過段,則不處理本次事件。直接return true;消費此次事件。
以對話方塊中攔截返回鍵舉例,增加返回鍵響應速度限制的程式碼如下。

setOnKeyListener(new OnKeyListener() {
    private static final int INTERVAL = 500;   //響應間隔時間
    private long lastReturnTime;               //上次響應返回事件時間
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK 
            && event.getAction() == KeyEvent.ACTION_UP) {
            long curTime = System.currentTimeMillis();
            if (curTime - lastReturnTime > INTERVAL) {
                lastReturnTime = curTime;
                ...
            } else {
                return true;
            }
        }
        return false;
    }
});