android listview焦点争端
2016-05-13 00:26
537 查看
listview没有响应事件,归根结底是因为listview的item条目中有Button 、ImageView、EditView等获取优先获取焦点的的子组件。,由于这样的子组件有更高的优先级获取焦点,所以传递过来的事件被消费了,而不再响应listview的触目事件。要想解决这个问题,必须分析出现这问题的原因。
在分析这个问题实现说明涉及到的三个方法dispatchTouchEvent(MotionEvent ev)【事件分发】、onInterceptTouchEvent(MotionEvent ev)【事件拦截】、onTouchEvent(MotionEvent
ev)【事件响应】。当然,能够响应这三个方法的控件包括:ViewGroup及其子类、Activity
ViewGroup能够响应三个方法,Activity不能够响应时间的拦截。还有如果view有子组件时,就可以响应三个方法,如果没有子控件的话,就只有事件响应的方法。
TouchEvent事件发生时,会从Activity的dispatchTouchEvent(MotionEvent ev)方法以隧道的方式【从根节点依次向下传递事件,直到最内层元素后者在中间某一元素停止传递】将事件传递给最外层View的dispatchTouchEvent(MotionEvent ev)方法进行分发。
dispatchTouchEvent(MotionEvent ev)的处理事件模型:
如果返回值为true,则由当前view的onTouchEvent(MotionEvent ev)消费事件,同时不再向下传递事件,以后所有的事件都会先传递到该view组件
如果返回值为false,假如事件直接来自Activity,则返回给Activity的onTouchEvent(MotionEvent ev)消费事件;否则返回给父的onTouchEvent(MotionEvent ev)消费事件
如果调用系统默认的super.dispatchTouchEvent(MotionEvent ev),事件会自动分发给当前的view的onInterceptTouchEvent(MotionEvent ev)方法
onInterceptTouchEvent(MotionEvent ev)的处理事件模型:
在外层的View的dispatchTouchEvent(MotionEvent ev)返回系统默认的super.dispatchTouchEvent(MotionEvent ev)情况下,事件会分发给当前的onInterceptTouchEvent(MotionEvent ev)的处理事件,判断是否·拦截事件。假如拦截事件事件传递到当前的onTouchEvent(MotionEvent ev)处理;否则,事件放行,将事件传递给子view的dispatchTouchEvent(MotionEvent ev)进行分发事件。当调用系统默认的super.onInterceptTouchEvent(MotionEvent
ev),默认事件被拦截
onTouchEvent(MotionEvent ev)的处理事件模型:
在dispatchTouchEvent(MotionEvent ev)返回super.dispatchTouchEvent(MotionEvent ev)和onInterceptTouchEvent(MotionEvent ev)返回true或者super.dispatchTouchEvent(MotionEvent ev)的时候,会被调用该事件。
如果当前返回false,则返回事件向上传递,有父类的onTouchEvent(MotionEvent ev)处理消费,父类也返回false就继续向上传递事件,直到顶层是件消失,而且也接收不到下一次事件
如果返回了true,则接受并消费事件
如果返回super.onTouchEvent(MotionEvent ev)则默认返回false,处理机制和上面返回false一样。
还有就是组件获取焦点的优先级:可以设置属性descendantFocusability,在item条目布局的根节点设置该属性
接受三个属性值:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
当然也可以设置子控件的Android:focusable="false"
聚焦分析:
当用户通过键盘(或者轨迹球)操作的时候,有必要聚焦当前接受输入的UI元素,但是有时候就不需要。比如触摸屏事件,点击某个UI元素也不会导致该元素聚焦,此时【高亮效果】由Pressed状态来标识,不会进入聚焦状态,即使调用requestFocus也不行的。
区分这两种情况需要TouchMode模式来标识。如果触摸事件,则进入该模式;否则调用View的isINTouchMode判断是否处于该模式下。
例外情况是,想EditView、Button这样的组件也会在触摸模式下获取焦点,这样会导致listview的事件无响应,先获取事件。可以调用在TouchMode模式也能获取焦点setFocusableInTouchMode(true),调用isFocusableInTouchMode是够可以获取焦点。
截断listview的item条目中优先获取焦点的方法为:
item条目的根目录下设置:
android:focusable="true" 【非触摸的属性】
android:focusableInTouchMode="true"
在分析这个问题实现说明涉及到的三个方法dispatchTouchEvent(MotionEvent ev)【事件分发】、onInterceptTouchEvent(MotionEvent ev)【事件拦截】、onTouchEvent(MotionEvent
ev)【事件响应】。当然,能够响应这三个方法的控件包括:ViewGroup及其子类、Activity
ViewGroup能够响应三个方法,Activity不能够响应时间的拦截。还有如果view有子组件时,就可以响应三个方法,如果没有子控件的话,就只有事件响应的方法。
TouchEvent事件发生时,会从Activity的dispatchTouchEvent(MotionEvent ev)方法以隧道的方式【从根节点依次向下传递事件,直到最内层元素后者在中间某一元素停止传递】将事件传递给最外层View的dispatchTouchEvent(MotionEvent ev)方法进行分发。
dispatchTouchEvent(MotionEvent ev)的处理事件模型:
如果返回值为true,则由当前view的onTouchEvent(MotionEvent ev)消费事件,同时不再向下传递事件,以后所有的事件都会先传递到该view组件
如果返回值为false,假如事件直接来自Activity,则返回给Activity的onTouchEvent(MotionEvent ev)消费事件;否则返回给父的onTouchEvent(MotionEvent ev)消费事件
如果调用系统默认的super.dispatchTouchEvent(MotionEvent ev),事件会自动分发给当前的view的onInterceptTouchEvent(MotionEvent ev)方法
onInterceptTouchEvent(MotionEvent ev)的处理事件模型:
在外层的View的dispatchTouchEvent(MotionEvent ev)返回系统默认的super.dispatchTouchEvent(MotionEvent ev)情况下,事件会分发给当前的onInterceptTouchEvent(MotionEvent ev)的处理事件,判断是否·拦截事件。假如拦截事件事件传递到当前的onTouchEvent(MotionEvent ev)处理;否则,事件放行,将事件传递给子view的dispatchTouchEvent(MotionEvent ev)进行分发事件。当调用系统默认的super.onInterceptTouchEvent(MotionEvent
ev),默认事件被拦截
onTouchEvent(MotionEvent ev)的处理事件模型:
在dispatchTouchEvent(MotionEvent ev)返回super.dispatchTouchEvent(MotionEvent ev)和onInterceptTouchEvent(MotionEvent ev)返回true或者super.dispatchTouchEvent(MotionEvent ev)的时候,会被调用该事件。
如果当前返回false,则返回事件向上传递,有父类的onTouchEvent(MotionEvent ev)处理消费,父类也返回false就继续向上传递事件,直到顶层是件消失,而且也接收不到下一次事件
如果返回了true,则接受并消费事件
如果返回super.onTouchEvent(MotionEvent ev)则默认返回false,处理机制和上面返回false一样。
还有就是组件获取焦点的优先级:可以设置属性descendantFocusability,在item条目布局的根节点设置该属性
接受三个属性值:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
当然也可以设置子控件的Android:focusable="false"
聚焦分析:
当用户通过键盘(或者轨迹球)操作的时候,有必要聚焦当前接受输入的UI元素,但是有时候就不需要。比如触摸屏事件,点击某个UI元素也不会导致该元素聚焦,此时【高亮效果】由Pressed状态来标识,不会进入聚焦状态,即使调用requestFocus也不行的。
区分这两种情况需要TouchMode模式来标识。如果触摸事件,则进入该模式;否则调用View的isINTouchMode判断是否处于该模式下。
例外情况是,想EditView、Button这样的组件也会在触摸模式下获取焦点,这样会导致listview的事件无响应,先获取事件。可以调用在TouchMode模式也能获取焦点setFocusableInTouchMode(true),调用isFocusableInTouchMode是够可以获取焦点。
截断listview的item条目中优先获取焦点的方法为:
item条目的根目录下设置:
android:focusable="true" 【非触摸的属性】
android:focusableInTouchMode="true"
相关文章推荐
- [Android]使用AIDL进行进程间通信
- Android_仿ios状态栏一体化
- Android启动界面之ViewPager用法详解
- Activity与Intent(一)
- Android开发者的福音-良心之选
- Android Weak Handler:可以避免内存泄漏的Handler库
- Android中使用Thread造成内存泄露的分析和解决
- php生成Android客户端扫描可登录的二维码
- Android控件笔记——多状态按钮ToggleButton
- Android控件笔记——CheckBox复选框
- Android控件笔记——使用RadioGroup和RadioButton实现单选效果
- Android中文API:Android 如何保持屏幕长亮?
- 你真的会用Android中Strings资源吗
- 【自用】Android 改变Bitmap图片资源为指定大小
- Android中用到的设计模式
- AndroidStudio降低编译版本报错
- Android基础——四大组件之Activity
- Android RGB颜色查询对照表
- Android进程间通信(IPC)之Messenger
- Android stadio 调试太掉了