在项目中碰到这样的问题: 
由于系统中的按键在底层做了重新定义或者新增了按键,此时需要在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,避免长按和单击事件混淆;

Android系统中自定义按键的短按、双击、长按事件的更多相关文章

  1. Android Tv 中的按键事件 KeyEvent 分发处理流程

    这次打算来梳理一下 Android Tv 中的按键点击事件 KeyEvent 的分发处理流程.一谈到点击事件机制,网上资料已经非常齐全了,像什么分发.拦截.处理三大流程啊:或者 dispatchTou ...

  2. Android系统中的广播(Broadcast)机制简要介绍和学习计划

    在Android系统中,广播(Broadcast)是在组件之间传播数据(Intent)的一种机制:这些组件甚至是可以位于不同的进程中,这样它就像Binder机制一样,起到进程间通信的作用:本文通过一个 ...

  3. Android系统中设置TextView的行间距(非行高)

    Android系统中TextView默认显示中文时会比较紧凑,不是很美观.为了让每行保持一定的行间距,可以设置属性android:lineSpacingExtra或android:lineSpacin ...

  4. Android系统对话框——自定义关闭

    Android系统对话框--自定义关闭 Dialog是我们在项目中经常用到的,5.x以后的Dialog也很好看,很安卓风,Android也给我们提供了新的包,低版本可以显示一样的效果.我们在使用的导入 ...

  5. AIDL在android系统中的作用

    AIDL,Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口.最近看了下AIDL在A ...

  6. Android系统中的6种模式

    Android系统中的6种模式 1:一般启动模式(normal mode):    功能是正常启动手机,方法为关机状态下按电源键启动. 2:安全模式(safe mode):    此模式和正常启动一样 ...

  7. [原创]Android系统中常用JAVA类源码浅析之HashMap

    由于是浅析,所以我只分析常用的接口,注意是Android系统中的JAVA类,可能和JDK的源码有区别. 首先从构造函数开始, /** * Min capacity (other than zero) ...

  8. Android系统中 setprop,getprop,watchprops命令的使用

    如:在frameworks/opt/net/ims/src/java/com/android/ims/ImsManager.java if (SystemProperties.get("pe ...

  9. 用adb pull命令从android系统中读取文件失败的原因及解决办法

    问题:使用adb pull命令从android系统中读取文件失败.显示:Permission denied   原因:是由于文件权限原因引起.       使用ls -l命令查看android系统中的 ...

随机推荐

  1. web自动化测试中绕开验证码登陆的方式

    web自动化测试中登陆需验证码是很大的一个困扰.现推荐一种简单的避开验证码登陆的方式,先代码进入登录页,人工输入验证码登录后浏览器自动保存cookie,再在新的标签中登录. 具体代码如下: publi ...

  2. SQL TOP 子句、SQL LIKE 操作符、SQL 通配符

    TOP 子句 TOP 子句用于规定要返回的记录的数目. 对于拥有数千条记录的大型表来说,TOP 子句是非常有用的. 注释:并非所有的数据库系统都支持 TOP 子句. SQL Server 的语法: S ...

  3. 月四 周2 iii

    同样发生于今天 今天做的一道题引起了我对<电波女与青春男>的回忆 如果说光鸟鸟和电波女对我来说有什么共同之处, 那应该是体验过程我都很认真吧 我还是很喜欢入间人间的书, 不过那本妹主题的新 ...

  4. FireDAC 连接SQL Server一些要注意的地方

    TFDConnection: FetchOptions.Mode 设置为fmAll, 返回全部结果, 否则默认只返回前50条, 效果与open以后再执行FetchAll一样 Specifies how ...

  5. css background-size 属性 兼容ie8 ie7 方案

    <!-- background-size-polyfill v0.2.0 | (c) 2012-2013 Louis-Rémi Babé | MIT License --> <PUB ...

  6. 为什么要使用CachedRowSetImpl?

    很多情况我们使用ResultSet 就会因为这样那样的问题,rs被关闭或数据链接被关闭,导致ResultSet不能使用.其实这个问题我们可以用CachedRowSetImpl来解决.我的理解是这是一个 ...

  7. iOS程序上传流程 2014年9月最新版

    程序上传步骤: 1.登录账户,点击Manage Your Apps 2.点击Add New App 3.注册Bundle ID,点击蓝色的here 4.进入了注册页面,首先要填写App ID的一个描述 ...

  8. OC ---- 字符串 数组 iOS学习-----细碎知识点总结

    NSString *urlString = [NSString stringWithFormat:@"http://www.apple.com"];        // 获取字符串 ...

  9. 使用CLion编辑C工程

    最近正在研究Linux C代码编辑器,确实也不太喜欢SI(Windows看代码还行,编辑一般,同步麻烦), 尝试使用CLion,但对makefile工程支持不好,怎么编译还没搞懂, 阅读.编辑还不错, ...

  10. git 添加 文件到GitHub

    用pycharm写代码,暂时不太了解它的版本控制方式,使用git托管到 GitHub. 1. 在被提交的文件夹下,运行 git  init,初始化git; 2. 添加需要提交的文件, git add ...