Android WindManager Addview 監聽按鍵事件

監聽 Home,Menu 按鍵的廣播

IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mContext.registerReceiver(mHomeListenerReceiver, filter);

private BroadcastReceiver mHomeListenerReceiver = new BroadcastReceiver() {
        final String SYSTEM_DIALOG_REASON_KEY = "reason";
        final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
        final String SYSTEM_DIALOG_REASON_RECENT_KEY = "recentapps";

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
            Log.d("TAG", "action:"+action+",reason:"+reason);
            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) &&
                    (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason) || SYSTEM_DIALOG_REASON_RECENT_KEY.equals(reason))) {

            }
        }
    };

WindowManage addView 監聽按鍵消息

直接使用 setOnKeyListener 監聽不到 OnKeyListener 事件的。

view. setOnKeyListener(new View.OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {

        return true;
    }
});

爲什麼呢?先來看看 ViewGroup 和 View 的 dispatchKeyEvent 源碼。

ViewGroup.java

public boolean dispatchKeyEvent(KeyEvent event) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onKeyEvent(event, 1);
    }

    if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
            == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
        if (super.dispatchKeyEvent(event)) {
            return true;
        }
    } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
            == PFLAG_HAS_BOUNDS) {
        if (mFocused.dispatchKeyEvent(event)) {
            return true;
        }
    }

    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
    }
    return false;
}

View.java

public boolean dispatchKeyEvent(KeyEvent event) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onKeyEvent(event, 0);
    }

    // Give any attached key listener a first crack at the event.
    //noinspection SimplifiableIfStatement
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
            && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
        return true;
    }

    if (event.dispatch(this, mAttachInfo != null
            ? mAttachInfo.mKeyDispatchState : null, this)) {
        return true;
    }

    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
    }
    return false;
}

查看 ViewGroup 和 View 的源碼可以知道,ViewGroup 要想響應 KeyEvent 事件。需要先判斷 mPrivateFlags 是否有 PFLAG_FOCUSED 和 PFLAG_HAS_BOUNDS 屬性。View 就沒有這個條件判斷。所以,我們在 Window 中添加 ViewGroup 時,如果沒有同時具備這兩個屬性。KeyEvent事件就不會傳遞下去。所以這也就導致我們的 ViewGroup 監聽不到 KeyEvent 事件。解決辦法就是重寫 dispatchKeyEvent 方法,這樣就繞過了 ViewGroup 的判斷條件。而添加 View 就不需要判斷這個條件了,因爲它不需要在判斷這兩個屬性了。通過 ViewGroup 和 View 的源碼,我們已經知道 dispatchKeyEvent 的分發機制了。所以,我們的 ViewGroup 要想監聽 KeyEvent事件。就需要重寫它的 dispatchKeyEvent 方法。

解決方法如下:

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (mOnKeyListener != null) {
        mOnKeyListener.onKey(this, event.getKeyCode(), event);
        return true;
    }

    return super.dispatchKeyEvent(event);
}

@Override
public void setOnKeyListener(OnKeyListener l) {
    super.setOnKeyListener(l);
    mOnKeyListener = l;
}

通過重寫父類的方法,我們就可以監聽到 Back 按鍵的事件了。

總結

監聽 Home,Menu,Back 等按鍵的事件消息。因爲 Home 和 Menu 按鍵的事件被系統處理掉了,我們只能通過監聽廣播的消息來處理其事件。而Back等其他按鍵的事件消息,如果我們的Window添加的是 ViewGrop 就需要重寫 dispatchKeyEvent 方法。

發佈了117 篇原創文章 · 獲贊 60 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章