zoukankan      html  css  js  c++  java
  • Android TouchEvent事件传递机制

    跟touch事件相关的3个方法:
    public boolean dispatchTouchEvent(MotionEvent ev);    //用来分派event
    public boolean onInterceptTouchEvent(MotionEvent ev); //用来拦截event
    public boolean onTouchEvent(MotionEvent ev);          //用来处理event
     
    拥有这三个方法的类:
    Activity类: Activity dispatchTouchEvent();
    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()方法来处理
    【注】:ViewGroup的某些子类(GridView、ScrollView...)重写了onInterceptTouchEvent()方法,当发生ACTION_MOVE事件时,返回true进行拦截。
     
    为了演示,重写了4个类:
    总统 --> MyActivity
    省长 --> MyFrameLayout
    市长 --> MyLinearLayout
    农民 --> MyTextView

     
    【举个通俗易懂的例子】:
    总统对省长说:我要吃红烧鱼
    省长对市长说:你做个红烧鱼
    市长对县长说:你做个红烧鱼
    县长对农民说:你做个红烧鱼
       ……(农民做呀做,没做出来)
    农民说:我尽力了,但真心不会做呀,饶了我吧
    县长说:你个笨蛋,下次不找你了,看我来做
       ……(县长做呀做,没做出来)
    县长对市长说:我尽力了,非常抱歉,我不会做
    市长说:你个废物,要你何用,只能我自己来做了
       ……(市长做呀做,做成功了)
    市长对省长说:红烧鱼做好了
    省长说:不错,下次有事还找你
    省长对总统说:红烧鱼做好了
    总统说:不错,下次有事还找你
    ---------------------------
    总统对省长说:我要吃水煮鱼
    省长对市长说:你做个水煮鱼
    市长说:县长连红烧鱼都搞不定,这次就不找他了,我自己亲自来做
     ……(市长做呀做,又成功了)
    市长对省长说:水煮鱼做好了
    省长说:不错,下次有事还找你
    省长对总统说:水煮鱼做好了
    总统说:不错,下次有事还找你
    ---------------------------
    • 按常理,领导都会把任务向下分派,一旦下面的人把事情做不好,就不会再把后续的任务交给下面的人来做了,只能自己亲自做,如果自己也做不了,就只能告诉上级不能完成任务,上级又会重复他的过程。
    • 另外,领导都有权利拦截任务,对下级隐瞒该任务,而直接自己去做,如果做不成,也只能向上级报告不能完成任务。
    【1】TextView的clickable属性默认是false,所以TextView的onTouchEvent()方法默认返回false,程序输出如下:
         事件传递示意图:

     
    【2】把TextView的clickable属性手动改成true,或者直接重写onTouchEvent()方法,使其返回true,程序输出如下:

          事件传递示意图:

     
    【3】手动重写LinearLayout的onInterceptTouchEvent()方法,使其返回true,拦截事件,再重写onTouchEvent()方法,返回true,程序输出:

          事件传递示意图:

     
    (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的。
    1. public class MyActivity extends Activity {  
    2.       
    3.     @Override  
    4.     public void onCreate(Bundle savedInstanceState) {  
    5.         super.onCreate(savedInstanceState);  
    6.         setContentView(R.layout.main);  
    7.     }  
    8.       
    9.     @Override  
    10.     public boolean dispatchTouchEvent(MotionEvent ev) {  
    11.         Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");  
    12.         return super.dispatchTouchEvent(ev);  
    13.     }  
    14.       
    15.     @Override  
    16.     public boolean onTouchEvent(MotionEvent ev) {  
    17.         boolean bo = false;  
    18.         Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 下面都解决不了,下次再也不能靠你们了,哼…只能自己尝试一下啦。能解决?" + bo);  
    19.         return bo;  
    20.     }  
    21. }  

    1. public class MyFrameLayout extends FrameLayout  
    2. {  
    3.     public MyFrameLayout(Context context, AttributeSet attrs){  
    4.         super(context, attrs);  
    5.     }  
    6.       
    7.     @Override  
    8.     public boolean dispatchTouchEvent(MotionEvent ev) {  
    9.         Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");  
    10.         return super.dispatchTouchEvent(ev);  
    11.     }  
    12.   
    13.     @Override  
    14.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
    15.         boolean bo = false;  
    16.         Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);  
    17.         return bo;  
    18.     }  
    19.   
    20.     @Override  
    21.     public boolean onTouchEvent(MotionEvent ev) {  
    22.         boolean bo = false;  
    23.         Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 市长是个废物,下次再也不找你了,我自己来尝试一下。能解决?" + bo);  
    24.         return bo;  
    25.     }  
    26. }  

    1. public class MyLinearLayout extends LinearLayout{  
    2.       
    3.     public MyLinearLayout(Context context, AttributeSet attrs) {  
    4.         super(context, attrs);  
    5.     }  
    6.       
    7.     @Override  
    8.     public boolean dispatchTouchEvent(MotionEvent ev) {  
    9.         Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");  
    10.         return super.dispatchTouchEvent(ev);  
    11.     }  
    12.   
    13.     @Override  
    14.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
    15.         boolean bo = false;  
    16.         Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);  
    17.         return bo;  
    18.     }  
    19.   
    20.     @Override  
    21.     public boolean onTouchEvent(MotionEvent ev) {  
    22.         boolean bo = false;  
    23.         Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 农民真没用,下次再也不找你了,我自己来尝试一下。能解决?" + bo);  
    24.         return bo;  
    25.     }  
    26. }  

    1. public class MyTextView extends TextView  
    2. {  
    3.     public MyTextView(Context context, AttributeSet attrs){  
    4.         super(context, attrs);  
    5.     }  
    6.       
    7.     @Override  
    8.     public boolean dispatchTouchEvent(MotionEvent ev){  
    9.         Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派,我下面没人了,怎么办?自己干吧");  
    10.         return super.dispatchTouchEvent(ev);  
    11.     }  
    12.       
    13.     @Override  
    14.     public boolean onTouchEvent(MotionEvent ev){  
    15.         boolean bo = true;  
    16.         Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 自己动手,埋头苦干。能解决?" + bo);  
    17.         return bo;  
    18.     }  
    19. }  
  • 相关阅读:
    LINUX查看硬件配置命令
    jmeter录制对于ip代理会失效
    性能测试常用指标
    jmeter使用jdbc获取注册验证码进行注册
    jmeter测试文件上传功能
    JMeter 功能挖掘之 WEB 文件导出
    分别用C/C++实现栈
    javascript的倒计时功能中newData().getTime()在iOS下会报错问题解决
    jquery解决file上传图片+图片预览
    使用SetInterval时函数不能传参问题
  • 原文地址:https://www.cnblogs.com/xiaorenwu702/p/4890870.html
Copyright © 2011-2022 走看看