1. 程式人生 > >Android系統中自定義按鍵的短按、雙擊、長按事件

Android系統中自定義按鍵的短按、雙擊、長按事件

在專案中碰到這樣的問題:
由於系統中的按鍵在底層做了重新定義或者新增了按鍵,此時需要在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、組合按鍵:用變數記錄每個按鍵的狀態,再進行判斷;

具體程式碼如下:
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,避免長按和單擊事件混淆;