Android事件的传递机制

Android事件构成

在Android中,事件主要包括点按、长按、拖拽、滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作。所有这些都构成了Android中的事件响应。总的来说,所有的事件都由如下三个部分作为基础:

按下(ACTION_DOWN)
移动(ACTION_MOVE)
抬起(ACTION_UP)
所有的操作事件首先必须执行的是按下操作(ACTIONDOWN),之后所有的操作都是以按下操作作为前提,当按下操作完成后,接下来可能是一段移动(ACTIONMOVE)然后抬起(ACTION_UP),或者是按下操作执行完成后没有移动就直接抬起。这一系列的动作在Android中都可以进行控制。

跟touch事件相关的3个方法

android系统中的每个ViewGroup的子类都具有下面三个和TouchEvent处理密切相关的方法:

1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent

2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent

3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent

注意:不是所有的View的子类,很多教程都说的是所有的View的子类,只有可以向里面添加View的控件才需要分发,比如TextView它本身就是最小的view了,所以不用再向它的子视图分发了,它也没有子视图了,所以它没有dispatch和Intercept,只有touchEvent。

拥有这三个方法的类:

这里写图片描述

布局控件方法
Activity类:ActivitydispatchTouchEvent();onTouchEvent();
View容器(ViewGroup的子类):FrameLayout、LinearLayout……ListView、ScrollVIew……dispatchTouchEvent();onInterceptTouchEvent();onTouchEvent();
View控件(非ViewGroup子类):Button、TextView、EditText……dispatchTouchEvent();onTouchEvent();

三个方法的用法:

dispatchTouchEvent()用来分派事件。其中调用onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法
onInterceptTouchEvent()用来拦截事件。ViewGroup类中的源码实现就是{return false;}表示不拦截该事件,事件将向下传递(传递给其子View);若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递,事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法
onTouchEvent()用来处理事件。返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View);返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理

为了演示,重写了4个类:

总统 –> MyActivity
省长 –> MyFrameLayout
市长 –> MyLinearLayout
农民 –> MyTextView

这里写图片描述

【举个通俗易懂的例子】:
这里写图片描述

按常理,领导都会把任务向下分派,一旦下面的人把事情做不好,就不会再把后续的任务交给下面的人来做了,只能自己亲自做,如果自己也做不了,就只能告诉上级不能完成任务,上级又会重复他的过程。
另外,领导都有权利拦截任务,对下级隐瞒该任务,而直接自己去做,如果做不成,也只能向上级报告不能完成任务。

要知道更详细的传递流程可查看:http://blog.csdn.net/morgan_xww/article/details/9372285

(1)这一系列的传递流程都是dispatchTouchEvent()方法来控制的,如果不人为地干预,事件将由上自下依次传递(因为默认是返回false不会拦截的),传递到最底层的View,就由它的onTouchEvent()方法来处理事件,若处理成功返回true,若处理失败返回false,事件依次向上传递,每个View都调用自己的onTouchEvent()方法来处理事件,若处理成功就终止传递,若处理失败就继续向上传递.
(2)经过人为的干预,若在向下传递的过程中被拦截了,即onInterceptTouchEvent()方法返回true,则事件将停止向下传递,直接由当前的onTouchEvent()方法来处理,若处理成功则OK,若处理不成功,则事件会向上传递。
(3)另外,dispatchTouchEvent()方法中还有“记忆”的功能,如果第一次事件向下传递到某View,它把事件继续传递交给它的子View,它会记录该事件是否被它下面的View给处理成功了,(怎么能知道呢?如果该事件会再次被向上传递到我这里来由我的onTouchEvent()来处理,那就说明下面的View都没能成功处理该事件);当第二次事件向下传递到该View,该View的dispatchTouchEvent()方法机会判断,若上次的事件由下面的view成功处理了,那么这次的事件就继续交给下面的来处理,若上次的事件没有被下面的处理成功,那么这次的事件就不会向下传递了,该View直接调用自己的onTouchEvent()方法来处理该事件。
(4)“记忆”功能的信息只在一系列事件完成之前有效,如从ACTION_DOWN事件开始,直到后续事件ACTION_MOVE,ACTION_UP结束后,“记忆”的信息就会清除。也就是说如果某View处理ACTION_DOWN事件失败了(onTouchEvent()返回false),那么后续的ACTION_MOVE,ACTION_UP等事件就不会再传递到该View了,由其父View自己来处理。在下一次发生ACTION_DOWN事件的时候,还是会传递到该View的。

代码

程序输出如下:
这里写图片描述

MyActivity

public class MyActivity extends Activity {  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
    }  

    @Override  
    public boolean dispatchTouchEvent(MotionEvent ev) {  
        Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");  
        return super.dispatchTouchEvent(ev);  
    }  

    @Override  
    public boolean onTouchEvent(MotionEvent ev) {  
        boolean bo = false;  
        Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 下面都解决不了,下次再也不能靠你们了,哼…只能自己尝试一下啦。能解决?" + bo);  
        return bo;  
    }  
}  

MyFrameLayout

public class MyFrameLayout extends FrameLayout  
{  
    public MyFrameLayout(Context context, AttributeSet attrs){  
        super(context, attrs);  
    }  

    @Override  
    public boolean dispatchTouchEvent(MotionEvent ev) {  
        Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");  
        return super.dispatchTouchEvent(ev);  
    }  

    @Override  
    public boolean onInterceptTouchEvent(MotionEvent ev) {  
        boolean bo = false;  
        Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);  
        return bo;  
    }  

    @Override  
    public boolean onTouchEvent(MotionEvent ev) {  
        boolean bo = false;  
        Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 市长是个废物,下次再也不找你了,我自己来尝试一下。能解决?" + bo);  
        return bo;  
    }  
}  

MyLinearLayout

public class MyLinearLayout extends LinearLayout{  

    public MyLinearLayout(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  

    @Override  
    public boolean dispatchTouchEvent(MotionEvent ev) {  
        Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");  
        return super.dispatchTouchEvent(ev);  
    }  

    @Override  
    public boolean onInterceptTouchEvent(MotionEvent ev) {  
        boolean bo = false;  
        Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);  
        return bo;  
    }  

    @Override  
    public boolean onTouchEvent(MotionEvent ev) {  
        boolean bo = false;  
        Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 农民真没用,下次再也不找你了,我自己来尝试一下。能解决?" + bo);  
        return bo;  
    }  
}  

MyTextView

public class MyTextView extends TextView  
{  
    public MyTextView(Context context, AttributeSet attrs){  
        super(context, attrs);  
    }  

    @Override  
    public boolean dispatchTouchEvent(MotionEvent ev){  
        Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派,我下面没人了,怎么办?自己干吧");  
        return super.dispatchTouchEvent(ev);  
    }  

    @Override  
    public boolean onTouchEvent(MotionEvent ev){  
        boolean bo = true;  
        Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 自己动手,埋头苦干。能解决?" + bo);  
        return bo;  
    }  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值