Android 事件分发keyEvent、touchEvent、hoverEvent
2016-02-17 16:02
537 查看
1、概述
上节介绍了android tv app 与android mobile app 的一些表现形式的不同。在实际编程中需要很多的焦点处理,而焦点处理有经常是在事件传递函数内处理的。所以本节做个android 事件传递与焦点处理的小结。另既然描述到android事件传递不可避免就涉及到了android手势拦截。这也是对原有知识认识的一个补充,因为之前涉及到安卓事件传递就是为了做手势拦截,以至于当看到代码在手势分发函数里处理tv的焦点,与界面移动填充时。一时有点迷糊,为什么是写在dispathKeyEvent里不是写在onInterceptTouchEvent里。原因就是因为这是在事件传递流程里处理焦点,而不是在事件传递流程里拦截事件。
2、Android简单的事件传递流程
提到android事件传递流程肯定会涉及到几个以下几个函数
函数
说明
备注
dispathTouchEvent (MotionEvent ev)
事件分发(手势分发)
触摸屏-手机
dispatchKeyEvent(KeyEvent event)
事件分发
遥控- tv
onInterceptTouchEvent
事件拦截(手势拦截)
返回true: 事件被拦截,事件传递给自己的
onTouchEvent
返回false:事件继续传递
ViewGroup才有
onTouchEvent
事件处理
返回true:事件被消费终止传递
返回false:继续传递
表1
Android事件传递有两种事件,一种是触摸屏的触摸事件,一种就是按键事件,键盘模式和遥控就用这种,不在熬述。dispathTouchEvent 和 dispatchKeyEvent 走的流程是一样的。
事件传递流程细节与源码的分析,网上有很多详细的描述,有些说的也是云里雾里,结合实际项目中的使用并参考:
PRE_andevcon_mastering-the-android-touch-system
事件传递从Activity的事件分发函数开始dispath… 如果没有事件消费最终在回到activty的ontouchEvent在子view被消费了,那就不会传到这个函数。
简单的Down事件的传递如下图和表1结合看:(事件未被消费)
图1
图2
关于拦截:对于拦截down事件后move/up 事件的传递比较复杂,实际使用中只要知道哪个view 是没有down事件的也就没有move/up 而且在实际项目中自己拦截的是move事件。onInterceptTouchEvent
public booleanonInterceptTouchEvent(MotionEvent ev)
事件拦截函数onInterceptTouchEvent是ViewGroup才有的函数。事件拦截(手势拦截)也是在自定义ViewGroup时才要做的。实际情况遇到的是,,对于move事件在一些边界使用条件的时候要决定是让ViewGroup自己处理还是childView来处理。其中通过返回值确定是否拦截,false继续传递,true拦截给自己,流程见图1,图2。
3、dispathKeyEvent 与 dispathTouchEvent
事件分发函数,也是事件流程的调度函数。基类的dispath…函数决定了事件传递的方式,里面有涉及到调用onInterceptTouchEvent,和onTouchEvent函数。
做自定ViewGroup事件拦截是不需要重写dispath…的只要重写onInterceptTouchEvent这个函数就可以。所以之前也比较少见重写dispath…
但是在tv app里好多地方是重写了该函数。开始的时候有点不明白为什么写在这里,后来看到每个dispathKeyEvent 函数都有调用super.dispathKeyEvent就明白了,重写dispathKeyEvent并没有影响事件的分发。只是相当于一个钩子挂在事件传递流程上来处理:点击按键手势时理焦点效果与界面效果,
4、焦点处理
手机app开发时焦点处理比较少,有就是editText有时候需要获取下焦点,或者移除下,其实也比较少处理。Tv里就比较多要处理,这里罗列下几个焦点处理函数
Activity
View currentView = getCurrentFocus();
ViewGroup
View currentView = findFocus();
View
currentView.focusSearch(direction);
找到指定方向最近的一个可获取焦点的view 如果没有返回null
setClickedAble
setFocusAble
电视遥控器,走key事件:
dispatchKeyEventPreIme、dispatchKeyEvent、onKeyDown、view.onKeyListener、view.onClickListener
> 对于key事件来说只有两个action:KeyEvent.ACTION_DOWN和KeyEvent.ACTION_UP
> Activity的dispatchKeyEvent 作为一切事件的入口。
[java]
view plain
copy
print?
public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();
Window win = getWindow();
if (win.superDispatchKeyEvent(event)) {
return true;
}
View decor = mDecor;
if (decor == null) decor = win.getDecorView();
return event.dispatch(this, decor != null
? decor.getKeyDispatcherState() : null, this);
}
那么就会将事件分发给decorView。(activity的decorView下的android.id.content就是咱们自己的layout的上层,是一个FrameLayout。)
> 在Activity的dispatchKeyEvent 消费某一事件(即return true)后,那onKeyDown则接收不到该事件
不消费则 return super.dispatchKeyEvent(event); (通常重写事件时,会有默认的返回方式,一般直接写最后,需要特殊处理并消费的地方才return true)
> 在View中:onKeyPreIme、onKeyDown、onKeyLongPress、onKeyUp、onKeyMultiple、onKeyShortcut(不清楚作嘛的)
还有dispatchKeyEventPreIme、dispatchKeyEvent
> 在ViewGroup中:dispatchKeyEventPreIme、dispatchKeyEvent
> dispatchKeyEventPreIme(在键盘Ime接收前执行) 会比 dispatchKeyEvent先执行,一般如果没有键盘输入的界面,重写任意一个都可以
> onClick:在一个完整的action_down和action_up周期后,才会执行onClick
> onKeyDown、onKeyListener 基本是一样的,只是看使用时候的范围,是要监听Activity,还是某一Layout,还是某一个View
总结:dispatch的会先执行,再到onKey;从Activity>ViewGroup(各式Layout)>view; 从action_down>action_up。
一个action_down,从activity的dispatch 往下分发,到viewGroup的dispatch。
dispath中return true,事件不再向后传
手机,走touch事件:
跟key类似,只是在ViewGroup中多了一个onInterceptTouchEvent。
dispatchTouchEvent>onInterceptTouchEvent>onTouchEvent
> dispath中return true,事件不再向后传
> onIntercept中return true,执行当前类的onTouchEvent,否则执行子类的dispatch
> onTouchEvent中 若在action_down后return true,后续执行move、up;
return false, 则后续的move、up执行不到了,传给父view,执行父view的touchEvent的action_down,
父view的dispatch-move、onTouch-move > 父view的dispatch-up、onTouch-up
鼠标,走hover事件:
在ViewGroup中多一个 onInterceptHoverEvent
鼠标有三种动作
> ACTION_HOVER_ENTER 指针悬浮在view上
> ACTION_HOVER_MOVE 指针在view上移动
> ACTION_HOVER_EXIT 指针离开view边界
鼠标目前没调试过,分发原理基本类似touch
1、概述
上节介绍了android tv app 与android mobile app 的一些表现形式的不同。在实际编程中需要很多的焦点处理,而焦点处理有经常是在事件传递函数内处理的。所以本节做个android 事件传递与焦点处理的小结。另既然描述到android事件传递不可避免就涉及到了android手势拦截。这也是对原有知识认识的一个补充,因为之前涉及到安卓事件传递就是为了做手势拦截,以至于当看到代码在手势分发函数里处理tv的焦点,与界面移动填充时。一时有点迷糊,为什么是写在dispathKeyEvent里不是写在onInterceptTouchEvent里。原因就是因为这是在事件传递流程里处理焦点,而不是在事件传递流程里拦截事件。
2、Android简单的事件传递流程
提到android事件传递流程肯定会涉及到几个以下几个函数
函数
说明
备注
dispathTouchEvent (MotionEvent ev)
事件分发(手势分发)
触摸屏-手机
dispatchKeyEvent(KeyEvent event)
事件分发
遥控- tv
onInterceptTouchEvent
事件拦截(手势拦截)
返回true: 事件被拦截,事件传递给自己的
onTouchEvent
返回false:事件继续传递
ViewGroup才有
onTouchEvent
事件处理
返回true:事件被消费终止传递
返回false:继续传递
表1
Android事件传递有两种事件,一种是触摸屏的触摸事件,一种就是按键事件,键盘模式和遥控就用这种,不在熬述。dispathTouchEvent 和 dispatchKeyEvent 走的流程是一样的。
事件传递流程细节与源码的分析,网上有很多详细的描述,有些说的也是云里雾里,结合实际项目中的使用并参考:
PRE_andevcon_mastering-the-android-touch-system
事件传递从Activity的事件分发函数开始dispath… 如果没有事件消费最终在回到activty的ontouchEvent在子view被消费了,那就不会传到这个函数。
简单的Down事件的传递如下图和表1结合看:(事件未被消费)
图1
图2
关于拦截:对于拦截down事件后move/up 事件的传递比较复杂,实际使用中只要知道哪个view 是没有down事件的也就没有move/up 而且在实际项目中自己拦截的是move事件。onInterceptTouchEvent
public booleanonInterceptTouchEvent(MotionEvent ev)
事件拦截函数onInterceptTouchEvent是ViewGroup才有的函数。事件拦截(手势拦截)也是在自定义ViewGroup时才要做的。实际情况遇到的是,,对于move事件在一些边界使用条件的时候要决定是让ViewGroup自己处理还是childView来处理。其中通过返回值确定是否拦截,false继续传递,true拦截给自己,流程见图1,图2。
3、dispathKeyEvent 与 dispathTouchEvent
事件分发函数,也是事件流程的调度函数。基类的dispath…函数决定了事件传递的方式,里面有涉及到调用onInterceptTouchEvent,和onTouchEvent函数。
做自定ViewGroup事件拦截是不需要重写dispath…的只要重写onInterceptTouchEvent这个函数就可以。所以之前也比较少见重写dispath…
但是在tv app里好多地方是重写了该函数。开始的时候有点不明白为什么写在这里,后来看到每个dispathKeyEvent 函数都有调用super.dispathKeyEvent就明白了,重写dispathKeyEvent并没有影响事件的分发。只是相当于一个钩子挂在事件传递流程上来处理:点击按键手势时理焦点效果与界面效果,
4、焦点处理
手机app开发时焦点处理比较少,有就是editText有时候需要获取下焦点,或者移除下,其实也比较少处理。Tv里就比较多要处理,这里罗列下几个焦点处理函数
Activity
View currentView = getCurrentFocus();
ViewGroup
View currentView = findFocus();
View
currentView.focusSearch(direction);
找到指定方向最近的一个可获取焦点的view 如果没有返回null
setClickedAble
setFocusAble
电视遥控器,走key事件:
dispatchKeyEventPreIme、dispatchKeyEvent、onKeyDown、view.onKeyListener、view.onClickListener
> 对于key事件来说只有两个action:KeyEvent.ACTION_DOWN和KeyEvent.ACTION_UP
> Activity的dispatchKeyEvent 作为一切事件的入口。
[java]
view plain
copy
print?
public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();
Window win = getWindow();
if (win.superDispatchKeyEvent(event)) {
return true;
}
View decor = mDecor;
if (decor == null) decor = win.getDecorView();
return event.dispatch(this, decor != null
? decor.getKeyDispatcherState() : null, this);
}
public boolean dispatchKeyEvent(KeyEvent event) { onUserInteraction(); Window win = getWindow(); if (win.superDispatchKeyEvent(event)) { return true; } View decor = mDecor; if (decor == null) decor = win.getDecorView(); return event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this); }上面是Activity中的源码。上面的代码说如果window自己消费了事件,那么return true。通常我们也不能把系统的window类改成这样。
那么就会将事件分发给decorView。(activity的decorView下的android.id.content就是咱们自己的layout的上层,是一个FrameLayout。)
> 在Activity的dispatchKeyEvent 消费某一事件(即return true)后,那onKeyDown则接收不到该事件
不消费则 return super.dispatchKeyEvent(event); (通常重写事件时,会有默认的返回方式,一般直接写最后,需要特殊处理并消费的地方才return true)
> 在View中:onKeyPreIme、onKeyDown、onKeyLongPress、onKeyUp、onKeyMultiple、onKeyShortcut(不清楚作嘛的)
还有dispatchKeyEventPreIme、dispatchKeyEvent
> 在ViewGroup中:dispatchKeyEventPreIme、dispatchKeyEvent
> dispatchKeyEventPreIme(在键盘Ime接收前执行) 会比 dispatchKeyEvent先执行,一般如果没有键盘输入的界面,重写任意一个都可以
> onClick:在一个完整的action_down和action_up周期后,才会执行onClick
> onKeyDown、onKeyListener 基本是一样的,只是看使用时候的范围,是要监听Activity,还是某一Layout,还是某一个View
总结:dispatch的会先执行,再到onKey;从Activity>ViewGroup(各式Layout)>view; 从action_down>action_up。
一个action_down,从activity的dispatch 往下分发,到viewGroup的dispatch。
dispath中return true,事件不再向后传
手机,走touch事件:
跟key类似,只是在ViewGroup中多了一个onInterceptTouchEvent。
dispatchTouchEvent>onInterceptTouchEvent>onTouchEvent
> dispath中return true,事件不再向后传
> onIntercept中return true,执行当前类的onTouchEvent,否则执行子类的dispatch
> onTouchEvent中 若在action_down后return true,后续执行move、up;
return false, 则后续的move、up执行不到了,传给父view,执行父view的touchEvent的action_down,
父view的dispatch-move、onTouch-move > 父view的dispatch-up、onTouch-up
鼠标,走hover事件:
在ViewGroup中多一个 onInterceptHoverEvent
鼠标有三种动作
> ACTION_HOVER_ENTER 指针悬浮在view上
> ACTION_HOVER_MOVE 指针在view上移动
> ACTION_HOVER_EXIT 指针离开view边界
鼠标目前没调试过,分发原理基本类似touch
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories