开发笔记:解决安卓GestureOverlayView手势和ListView点击事件、文本框获取焦点冲突的问题
2013-12-13 17:40
746 查看
要解决这个问题,首先要弄清楚几个问题:
1、onThouch事件的触发原理是怎样的?
2、GestureOverlayView的绘制手势的事件是在什么时候触发的?
3、父子嵌套的控件触发事件的顺序是怎样的?
4、父子控件获取焦点的顺序是怎样的?
第一个问题,安卓中任何控件的onThouch事件触发的时候,都经过了以下过程:
public boolean dispatchTouchEvent(MotionEvent ev) ,该方法如果返回true,则事件在该位置被消费掉,不再向下传递,返回false则继续传递至
public boolean onInterceptTouchEvent(MotionEvent ev)这个方法,该方法是事件拦截器,如果返回true,则触发该控件的onThouch事件,否则就将事件传递给该控件的子控件,
public boolean onTouchEvent(MotionEvent ev),返回true的话就消费掉该事件,返回false就传递到该控件的父控件的onThouch事件
在网上找到一个图片,能简洁明了的反映以上关系:
第二个问题,查看GestureOverlayView源码可知道,手势绘制的监听触发时间是在dispatchTouchEvent(MotionEvent ev)这个事件中就完成的,所以只要有触摸屏幕的动作,就必然会被它先消费掉,这也是手势事件和其他控件冲突的根本原因~源码如下:
基于这个原因,可能很多人会考虑通过重写GestureOverlayView控件来解决冲突问题,我也试过了,但是依然不能解决较为复杂的问题,所以在次就不再赘述了。
第三个问题,借用一篇博客来说明问题,在此感谢博主 @浅秋/article/2242084.html(博文写的很详细)
借用第三个问题,第四个问题就迎刃而解了,可以简单的理解为,正常情况下,最内层的控件是最先获取焦点的,
最外层的是最后获取焦点的;但是最外层的获取焦点的优先级是最高的,一旦它决定拦截并消费事件,那么它的子控件就不能再获取该事件;
解决冲突的方法:
我的需求是在一个ListView页面启用手势功能,
用户如果画了手势,则根据手势内容做不同的反应,但是手势不能影响ListView的滚动、点击、选中的操作;
ListView中包含文本框;如果点击的是文本框,不能影响文本框获取焦点进行编辑;
我重写GestureOverlayView的时候解决了前2个需求,但是文本框死活获取不了焦点;
布局文件如下,需要说明是,因为之前是通过重写来做的,但是最后没解决,于是重写的文件直接调用了super,等于没重写:
重写的时候,我用MGestureOverlayView包含了ListView,
但是后来一想,因为MGestureOverlayView每次都会最先拦截,并且它必然会消费事件,所以这样肯定是不行的,
于是就换成并列的,解决方法就是,在MGestureOverlayView的onThouch事件中,手动赋予ListView的事件源,代码如下
同时重写ListView的onInterceptTouchEvent方法,让其直接返回false
(这步好像不是必须的,忘记了 >_< ,默认的貌似就是返回false)
1、onThouch事件的触发原理是怎样的?
2、GestureOverlayView的绘制手势的事件是在什么时候触发的?
3、父子嵌套的控件触发事件的顺序是怎样的?
4、父子控件获取焦点的顺序是怎样的?
第一个问题,安卓中任何控件的onThouch事件触发的时候,都经过了以下过程:
public boolean dispatchTouchEvent(MotionEvent ev) ,该方法如果返回true,则事件在该位置被消费掉,不再向下传递,返回false则继续传递至
public boolean onInterceptTouchEvent(MotionEvent ev)这个方法,该方法是事件拦截器,如果返回true,则触发该控件的onThouch事件,否则就将事件传递给该控件的子控件,
public boolean onTouchEvent(MotionEvent ev),返回true的话就消费掉该事件,返回false就传递到该控件的父控件的onThouch事件
在网上找到一个图片,能简洁明了的反映以上关系:
第二个问题,查看GestureOverlayView源码可知道,手势绘制的监听触发时间是在dispatchTouchEvent(MotionEvent ev)这个事件中就完成的,所以只要有触摸屏幕的动作,就必然会被它先消费掉,这也是手势事件和其他控件冲突的根本原因~源码如下:
@Override public boolean dispatchTouchEvent(MotionEvent event) { if (isEnabled()) { final boolean cancelDispatch = (mIsGesturing || (mCurrentGesture != null && mCurrentGesture.getStrokesCount() > 0 && mPreviousWasGesturing)) && mInterceptEvents; processEvent(event); if (cancelDispatch) { event.setAction(MotionEvent.ACTION_CANCEL); } super.dispatchTouchEvent(event); return true; } return super.dispatchTouchEvent(event); } private boolean processEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchDown(event); invalidate(); return true; case MotionEvent.ACTION_MOVE: if (mIsListeningForGestures) { Rect rect = touchMove(event); if (rect != null) { invalidate(rect); } return true; } break; case MotionEvent.ACTION_UP: if (mIsListeningForGestures) { touchUp(event, false); invalidate(); return true; } break; case MotionEvent.ACTION_CANCEL: if (mIsListeningForGestures) { touchUp(event, true); invalidate(); return true; } } return false; }
基于这个原因,可能很多人会考虑通过重写GestureOverlayView控件来解决冲突问题,我也试过了,但是依然不能解决较为复杂的问题,所以在次就不再赘述了。
第三个问题,借用一篇博客来说明问题,在此感谢博主 @浅秋/article/2242084.html(博文写的很详细)
借用第三个问题,第四个问题就迎刃而解了,可以简单的理解为,正常情况下,最内层的控件是最先获取焦点的,
最外层的是最后获取焦点的;但是最外层的获取焦点的优先级是最高的,一旦它决定拦截并消费事件,那么它的子控件就不能再获取该事件;
解决冲突的方法:
我的需求是在一个ListView页面启用手势功能,
用户如果画了手势,则根据手势内容做不同的反应,但是手势不能影响ListView的滚动、点击、选中的操作;
ListView中包含文本框;如果点击的是文本框,不能影响文本框获取焦点进行编辑;
我重写GestureOverlayView的时候解决了前2个需求,但是文本框死活获取不了焦点;
布局文件如下,需要说明是,因为之前是通过重写来做的,但是最后没解决,于是重写的文件直接调用了super,等于没重写:
<ListView android:id="@+id/list_aj" android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" android:longClickable="true" /> <TextView android:id="@+id/textViewModel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" /> <EditText android:id="@+id/textViewValueModel" android:layout_width="300dp" android:layout_height="40dip" android:layout_centerVertical="true" android:gravity="center_vertical" android:layout_marginLeft="110dip" android:textSize="17sp" android:background="@null" android:inputType="text" android:focusable="false" android:visibility="gone" /> <ImageView android:id="@+id/imageViewModel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:contentDescription="@string/descTask" android:layout_centerVertical="true"/> <com.zbtc_it.tcis.Util.MGestureOverlayView calss="com.zbtc_it.tcis.Util.MGestureOverlayView" android:id="@+id/gesture" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" > </com.zbtc_it.tcis.Util.MGestureOverlayView>
重写的时候,我用MGestureOverlayView包含了ListView,
但是后来一想,因为MGestureOverlayView每次都会最先拦截,并且它必然会消费事件,所以这样肯定是不行的,
于是就换成并列的,解决方法就是,在MGestureOverlayView的onThouch事件中,手动赋予ListView的事件源,代码如下
overlays = (MGestureOverlayView) layout.findViewById(R.id.gesture); overlays.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE); overlays.setFadeOffset(1000);// 多笔画2笔之间的时间间隔 overlays.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { itemListView.dispatchTouchEvent(event);//赋予ListView事件源 return false;//消费掉事件 } });
同时重写ListView的onInterceptTouchEvent方法,让其直接返回false
(这步好像不是必须的,忘记了 >_< ,默认的貌似就是返回false)
相关文章推荐
- 自定义TextView解决事件冲突TextView不能获取焦点问题
- 自定义SwipeRefreshLayout 嵌套listview 并解决item点击事件焦点冲突问题
- 解决UITapGestureRecognizer手势与UITableView的点击事件的冲突
- RecyclerView嵌套ListView解决点击事件问题
- 如何解决listView或scrollView+viewpager手势冲突的问题
- Unity上路(一):Srollview的Cell点击与滑动事件冲突的问题解决
- 安卓解决viewPager+scrollView+listView滑动冲突的问题
- listview item中button点击事件和listview onItem点击事件冲突问题解决
- UITapGestureRecognizer和UITableView点击事件冲突问题
- Android ListView焦点事件冲突问题与解决
- TV中RecyclerView添加item的点击事件和删除item之后获取焦点解决
- 解决 Android WebView 文本框获取焦点后自动放大问题
- ListView里面有EditTextView,解决弹出键盘后EditView不能获取焦点的问题
- 解决UITapGestureRecognizer 与 UITableView 点击事件冲突
- Listview点击事件失效问题解决以及每个Item 子控件获取focus
- 解决手势与tableview点击事件冲突:
- android开发步步为营之65:解决ScrollView和ListView触摸事件onInterceptTouchEvent相互冲突问题
- 解决ScrollView嵌套viewPager中嵌套listView滑动事件冲突问题(水平方向)
- android开发步步为营之65:解决ScrollView和ListView触摸事件onInterceptTouchEvent相互冲突问题
- AndroidTV/机顶盒 ListView获取焦点与点击事件问题处理方案