• 【转】Android TouchEvent事件传递机制


    Android TouchEvent事件传递机制
     
    事件机制参考地址:
      http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html
      http://www.blogjava.net/TiGERTiAN/archive/2011/02/22/344869.html
      http://blog.csdn.net/morgan_xww/article/details/9372285
    跟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     }  


    原文地址:http://blog.csdn.net/morgan_xww/article/details/9372285

     
    时间传递机制强化(直接上代码,能拖动的ImageView(默认的点击事件是false)和Button(默认点击事件是true))
      1 public class MainActivity extends Activity implements OnTouchListener {
      2 
      3     private ImageView img;
      4 
      5     private int lastX, lastY;
      6 
      7     private int screenWidth, screenHeight;
      8 
      9     @Override
     10     protected void onCreate(Bundle savedInstanceState) {
     11         super.onCreate(savedInstanceState);
     12         setContentView(R.layout.activity_main);
     13         img = (ImageView) findViewById(R.id.img);
     14         // 获取屏幕的宽和高
     15         DisplayMetrics dm = getResources().getDisplayMetrics();
     16         screenWidth = dm.widthPixels;
     17         screenHeight = dm.heightPixels;
     18         System.out.println("screenWidth-->>" + screenWidth
     19                 + "    screenHeight-->>" + screenHeight);
     20         img.setOnTouchListener(new OnTouchListener() {
     21 
     22             @Override
     23             public boolean onTouch(View v, MotionEvent event) {
     24                 System.out.println("这是ImageView的onTouch");
     25                 switch (event.getAction()) {
     26                 case MotionEvent.ACTION_DOWN:
     27                     lastX = (int) event.getRawX();
     28                     lastY = (int) event.getRawY();
     29 
     30                     /**
     31                      * 如果这里返回true 或者让ImageView
     32                      * 的android:onClick设置成true(表示down时间处理成功了)
     33                      * 在结合时间传递机制就知道为什么了Down-->>move-->>up
     34                      */
     35                     return false;
     36 
     37                 case MotionEvent.ACTION_MOVE:
     38                     int dx = (int) (event.getRawX() - lastX);
     39                     int dy = (int) (event.getRawY() - lastY);
     40 
     41                     int left = v.getLeft() + dx;
     42                     int top = v.getTop() + dy;
     43                     int right = v.getRight() + dx;
     44                     int bottom = v.getBottom() + dy;
     45 
     46                     if (left <= 0) {
     47                         // 到达父View的左边界
     48                         left = 0;
     49                         right = left + v.getWidth();
     50                     }
     51 
     52                     if (right >= screenWidth) {
     53                         right = screenWidth;
     54                         left = right - v.getWidth();
     55                     }
     56 
     57                     if (top <= 0) {
     58                         top = 0;
     59                         bottom = top + v.getHeight();
     60                     }
     61 
     62                     if (bottom >= screenHeight) {
     63                         bottom = screenHeight;
     64                         top = bottom - v.getHeight();
     65                     }
     66 
     67                     v.layout(left, top, right, bottom);
     68                     lastX = (int) event.getRawX();
     69                     lastY = (int) event.getRawY();
     70                 case MotionEvent.ACTION_UP:
     71 
     72                     System.out.println("释放后的位置-->>event.getX():" + event.getX()
     73                             + "   event.getY():" + event.getY()
     74                             + "  event.getRawX():" + event.getRawX()
     75                             + "   event.getRawY():" + event.getRawY());
     76 
     77                     break;
     78 
     79                 default:
     80 
     81                     break;
     82                 }
     83 
     84                 return false;
     85             }
     86 
     87         });
     88 
     89         findViewById(R.id.btn).setOnTouchListener(new OnTouchListener() {
     90 
     91             @Override
     92             public boolean onTouch(View v, MotionEvent event) {
     93                 System.out.println("这是Button的onTouch");
     94                 switch (event.getAction()) {
     95                 case MotionEvent.ACTION_DOWN:
     96                     System.out
     97                             .println("ACTION_DOWNACTION_DOWNACTION_DOWNACTION_DOWNACTION_DOWN");
     98                     lastX = (int) event.getRawX();
     99                     lastY = (int) event.getRawY();
    100                     break;
    101 
    102                 case MotionEvent.ACTION_MOVE:
    103                     System.out.println("MOVEMOVE");
    104                     int dx = (int) (event.getRawX() - lastX);
    105                     int dy = (int) (event.getRawY() - lastY);
    106 
    107                     int left = v.getLeft() + dx;
    108                     int top = v.getTop() + dy;
    109                     int right = v.getRight() + dx;
    110                     int bottom = v.getBottom() + dy;
    111 
    112                     if (left <= 0) {
    113                         // 到达父View的左边界
    114                         left = 0;
    115                         right = left + v.getWidth();
    116                     }
    117 
    118                     if (right >= screenWidth) {
    119                         right = screenWidth;
    120                         left = right - v.getWidth();
    121                     }
    122 
    123                     if (top <= 0) {
    124                         top = 0;
    125                         bottom = top + v.getHeight();
    126                     }
    127 
    128                     if (bottom >= screenHeight) {
    129                         bottom = screenHeight;
    130                         top = bottom - v.getHeight();
    131                     }
    132 
    133                     v.layout(left, top, right, bottom);
    134                     lastX = (int) event.getRawX();
    135                     lastY = (int) event.getRawY();
    136 
    137                     break;
    138                 case MotionEvent.ACTION_UP:
    139 
    140                     System.out.println("释放后的位置-->>event.getX():" + event.getX()
    141                             + "   event.getY():" + event.getY()
    142                             + "  event.getRawX():" + event.getRawX()
    143                             + "   event.getRawY():" + event.getRawY());
    144                     break;
    145 
    146                 default:
    147 
    148                     break;
    149                 }
    150                 return false;
    151             }
    152 
    153         });
    154 
    155     }
    156 
    157     @Override
    158     public boolean onTouch(View v, MotionEvent event) {
    159         System.out.println("这是Activity的onTouch");
    160         return false;
    161     }
    162 
    163 }
    activity_main.xml
     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical"
     6     tools:context=".MainActivity" >
     7 
     8     <ImageView
     9         android:id="@+id/img"
    10         android:layout_width="wrap_content"
    11         android:layout_height="wrap_content"
    12         android:contentDescription="图片"
    13         android:focusable="true"
    14         android:focusableInTouchMode="true"
    15         android:src="@drawable/ic_launcher" >
    16     </ImageView>
    17 
    18     <Button
    19         android:id="@+id/btn"
    20         android:layout_width="wrap_content"
    21         android:layout_height="wrap_content"
    22         android:text="拖动试一试" />
    23 
    24 </LinearLayout>

    代码:http://pan.baidu.com/s/1gdiVayJ

  • 相关阅读:
    ocx手动添加自定义消息
    ocx手动添加方法
    ocx手动添加事件
    c判断文件是否存在
    unity hub 更新之后,出现了好多问题。
    asp.net core系列 77 webapi响应压缩
    python:生成半年内的巡检日报execl
    python:selenium爬取boss网站被关小黑屋
    k8s 批量安装脚本
    sysctl: cannot stat /proc/sys/net/bridge/bridgenfcallip6tables: No such file or directory
  • 原文地址:https://www.cnblogs.com/liangstudyhome/p/3798638.html
Copyright © 2020-2023  润新知