在項目中碰到這樣的問題:
由於系統中的按鍵在底層做了重新定義或者新增了按鍵,此時需要在APP層對按鍵事件(keyevent)做分解處理,模擬Android系統做法,把keyevent分解成:
1、單擊事件:就是普通key的單擊;
2、雙擊事件:500ms內同一按鍵單擊兩次;
3、長按事件:同一按鍵長按超過1000ms(系統中長按事件為500ms);
4、組合按鍵:兩個以上按鍵同時按住;
其中的keyevent可以來自Activity、View子類的dispatchKeyEvent方法,也可以是我們自定義的接口,也可以是我們發廣播送上來的,根據項目需求;
關於各事件的原理:
1、雙擊事件:每次點擊的up事件中啟動一個定時(500ms)線程消息,用Handler.postDelayed()方法。
2、長按事件:每次點擊的down事件中啟動一個定時(1000ms)線程消息,用Handler.postDelayed()方法,注意:在RepeatCount==0時啟動;
3、組合按鍵:用變量記錄每個按鍵的狀態,再進行判斷;
具體代碼如下: Java代碼
package com.jerome.util; import android.content.Context; import android.os.Handler; import android.util.Log; import android.view.KeyEvent; public class KeyUtil { private boolean isVolumeDown = false; private boolean isVolumeUp = false; private boolean isMenu = false; private int currentKeyCode = 0; private static Boolean isDoubleClick = false; private static Boolean isLongClick = false; CheckForLongPress mPendingCheckForLongPress = null; CheckForDoublePress mPendingCheckForDoublePress = null; Handler mHandler = new Handler(); Context mContext = null; private String TAG = ""; public KeyUtil(Context context, String tag) { mContext = context; TAG = tag; } public void dispatchKeyEvent(KeyEvent event) { int keycode = event.getKeyCode(); // 有不同按鍵按下,取消長按、短按的判斷 if (currentKeyCode != keycode) { removeLongPressCallback(); isDoubleClick = false; } // 處理長按、單擊、雙擊按鍵 if (event.getAction() == KeyEvent.ACTION_DOWN) { checkForLongClick(event); } else if (event.getAction() == KeyEvent.ACTION_UP) { checkForDoubleClick(event); } if (keycode == KeyEvent.KEYCODE_VOLUME_DOWN) { if (event.getAction() == KeyEvent.ACTION_DOWN) { isVolumeDown = true; } else if (event.getAction() == KeyEvent.ACTION_UP) { isVolumeDown = false; } } else if (keycode == KeyEvent.KEYCODE_VOLUME_UP) { if (event.getAction() == KeyEvent.ACTION_DOWN) { isVolumeUp = true; } else if (event.getAction() == KeyEvent.ACTION_UP) { isVolumeUp = false; } } else if (keycode == KeyEvent.KEYCODE_MENU) { if (event.getAction() == KeyEvent.ACTION_DOWN) { isMenu = true; } else if (event.getAction() == KeyEvent.ACTION_UP) { isMenu = true; } } // 判斷組合按鍵 if (isVolumeDown && isVolumeUp && isMenu && (keycode == KeyEvent.KEYCODE_VOLUME_UP || keycode == KeyEvent.KEYCODE_VOLUME_DOWN || keycode == KeyEvent.KEYCODE_MENU) && event.getAction() == KeyEvent.ACTION_DOWN) { //組合按鍵事件處理; isVolumeDown = false; isVolumeUp = false; isMenu = false; } } private void removeLongPressCallback() { if (mPendingCheckForLongPress != null) { mHandler.removeCallbacks(mPendingCheckForLongPress); } } private void checkForLongClick(KeyEvent event) { int count = event.getRepeatCount(); int keycode = event.getKeyCode(); if (count == 0) { currentKeyCode = keycode; } else { return; } if (mPendingCheckForLongPress == null) { mPendingCheckForLongPress = new CheckForLongPress(); } mPendingCheckForLongPress.setKeycode(event.getKeyCode()); mHandler.postDelayed(mPendingCheckForLongPress, 1000); } class CheckForLongPress implements Runnable { int currentKeycode = 0; public void run() { isLongClick = true; longPress(currentKeycode); } public void setKeycode(int keycode) { currentKeycode = keycode; } } private void longPress(int keycode) { Log.i(TAG, "--longPress 長按事件--" + keycode); } private void singleClick(int keycode) { Log.i(TAG, "--singleClick 單擊事件--" + keycode); } private void doublePress(int keycode) { Log.i(TAG, "---doublePress 雙擊事件--" + keycode); } private void checkForDoubleClick(KeyEvent event) { // 有長按時間發生,則不處理單擊、雙擊事件 removeLongPressCallback(); if (isLongClick) { isLongClick = false; return; } if (!isDoubleClick) { isDoubleClick = true; if (mPendingCheckForDoublePress == null) { mPendingCheckForDoublePress = new CheckForDoublePress(); } mPendingCheckForDoublePress.setKeycode(event.getKeyCode()); mHandler.postDelayed(mPendingCheckForDoublePress, 500); } else { // 500ms內兩次單擊,觸發雙擊 isDoubleClick = false; doublePress(event.getKeyCode()); } } class CheckForDoublePress implements Runnable { int currentKeycode = 0; public void run() { if (isDoubleClick) { singleClick(currentKeycode); } isDoubleClick = false; } public void setKeycode(int keycode) { currentKeycode = keycode; } } private void removeDoublePressCallback() { if (mPendingCheckForDoublePress != null) { mHandler.removeCallbacks(mPendingCheckForDoublePress); } } }
注意:
只有Action Down狀態下RepeatCount才會>0,避免長按和單擊事件混淆;