码迷,mamicode.com
首页 > 移动开发 > 详细

【自定义控件】android事件分发机制

时间:2015-08-12 16:56:30      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:事件传递机制   控件   移动   android   事件冲突   

自定义控件中我们经常也许会经常碰到这样的情况,自己加了一些点击,滑动的事件的处理判断导致另外一些控件点击,滑动没有用了,滑动反应反应很慢,要划很多次猜移动一点点等等。也许我们第一反应就是百度,google去搜索下答案,把代码直接copy过来。其实也许可以换个解决办法,自己想想为什么会出现这种情况。

以下是博主对android事件分发机制的初步探索。希望大家看完后能对Android事件分发机制有一个详细的了解,以后不用百度,google也能轻松解决由于事件冲突导致各种问题。

首先我们要对Android 事件有初步的了解:

1.Android  Touch事件相关的函数包括了:

dispatchTouchEvent(MotionEvent ev):负责事件分发的函数,在各个view里面最先被调用

onInterceptTouchEvent(MotionEvent ev) :事件拦截的函数(viewGroupf非常重要函数,下面会有具体说明)

onTouchEvent(MotionEvent ev):事件响应的函数

onTouch(MotionEvent ev):事件相应的函数

onTouchEvent(MotionEvent ev)和onTouch(MotionEvent ev)均是事件响应的函数,2者区别:onTouch会优先于onTouchEvent调用,onTouch只有在listener不为空与点击的控件为enable的情况下会被调用,onTouch能通过控件外部传入onTouchListener来实现监听,而onTouchEvent不能通过外部设置。(可能描述过于抽象,简单点就是有些控件没有ontouch事件,或者控件不可点击那么我们想监听onTouch事件就必须重写onTouchEvent来实现监听)


请看以下view的dispatchTouchEvent源码中调用onTouch()和onTouchEvent()的区别:


if (onFilterTouchEventForSecurity(event)) {
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
外层判断暂时不管(用来判断view是否位于顶部的,如果view不在顶部,过滤掉用点击事件),请注意内层判断,当mListenerInfo中的mOnTouchListener不为空(即我们给view注册了监听事件)并且view是可点击的就把事件交给mListenerInfo的mOnTouchListener.onTouch来处理并且根据onTouchListener的boolean来决定事件是否继续传递,根据result的值来决定是否调用onTouchEvent

返回值说明:当dispatchTouchEvent(MotionEvent ev)返回为false表示继续向上传递,true表示停止传递

以下是事件传递的顺序:


假定我们有一个LinearLayout,   布局中有一个Button。那么touch事件的传递如下:


activity的dispatchTouchEvent()------>LinearLayout的dispatchTouchEvent()--------->onInterceptTouchEvent()------->button的dispatchTouchEvent()从根元素向上依次传递,如果中间我们重写了某view的dispatchTouchEvent()并且返回true,那么事件会停止继续传递并且由当前函数消费。onTouch和onTouchEvent一样的道理(这两者区别见上面描述),只是顺序正好和dispatchTouchEvent的顺序相反,从最外层向根元素传递。


至于onInterceptTouchEvent(),首先该函数是ViewGroup的函数,也意味着只有ViewGroup和该类的子类中可以重写该函数,例如我们自定义的view继承自LinearLayout(LinearLayout为ViewGroup的子类),那么我们就可以重写该函数来达到事件拦截的目的,该函数紧跟dispatchTouchEvent()后调用(前提是该函数存在,默认返回false),如果onInterceptTouchEvent()返回为false 事件会继续传递,如果返回为true,那么事件将停止继续向上面的dispatchTouchEvent()并且将事件交给自己的onTouch()和onTouchEvent()来处理。

下面我们来看下实验的结果

1.没有改变事件返回的结果

技术分享

事件最终被customButton消费掉了,从中我们可以得到以下事件传递的图

技术分享


2.重写onInterceptTouchEvent,并且返回为true截断事件继续传递


技术分享

这里需要说明下由于在coustomLinearLayout中事件没有被消费掉(也就是Touch相关函数全部返回为false),如果是activity分发下去的事件那么最终会到由activity onTouchEvent()消费掉,下面是调用的示意图

技术分享


3.CustomButton的onTouchEvent()返回false

技术分享


技术分享


4.点击在CustomLinearLayout上,没有点击到CustomButton


技术分享


技术分享

从上面我们可以得到

1.除了onInterceptTouchEvent()外,其他事件按照1所示依次由根元素传递给点击的view,并且由view消费掉,并且中间环节任意一个函数返回了true(除了onInterceptTouchEvent()外),那么事件将会由当前返回true的函数消费,停止向后面传递,由于函数过多,博主就没有把每个函数返回true的情况截图贴出来了。

2.ViewGroup的子类中,重写onInterceptTouchEvent()函数,返回为true,那么该函数将停止向子view的dispatchTouchEvent()传递,并把事件交由当前view的onTouch()和onTouchEvent()处理

3.view的onTouchEvent默认会消费掉事件,ViewGroup的0nTouchEvent则不会消费掉事件

4.同级别view,会根据你点击的控件来进行事件传递,传递到相应的你点击的view,如果点击的是ViewGroup,那么事件将不会被消费掉,直到传递到分发的根元素的OnTouchEvent()才会被消费掉


掌握了以上的的事件传递的基本知识,下次我们碰到事件冲突就可以尝试自己去解决了!

版权声明:本文为博主原创文章,未经博主允许不得转载。

【自定义控件】android事件分发机制

标签:事件传递机制   控件   移动   android   事件冲突   

原文地址:http://blog.csdn.net/q849340003/article/details/47419609

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!