zoukankan      html  css  js  c++  java
  • 【转】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

  • 相关阅读:
    ZOJ 1002 Fire Net (火力网)
    UVa OJ 117 The Postal Worker Rings Once (让邮差只走一圈)
    UVa OJ 118 Mutant Flatworld Explorers (变体扁平世界探索器)
    UVa OJ 103 Stacking Boxes (嵌套盒子)
    UVa OJ 110 MetaLoopless Sorts (无循环元排序)
    第一次遇到使用NSNull的场景
    NSURL使用浅析
    从CNTV下载《小小智慧树》
    NSDictionary and NSMutableDictionary
    Category in static library
  • 原文地址:https://www.cnblogs.com/liangstudyhome/p/3798638.html
Copyright © 2011-2022 走看看