Android系统中TouchEvent的传递流程以及相关函数返回值True和False对流程的影响

来源:互联网 发布:mac怎么连接打印机 编辑:程序博客网 时间:2024/05/22 14:32
3个关键函数

booleandispatchTouchEvent(MotionEvent ev)

booleanonInterceptTouchEvent(MotionEvent ev)

booleanonTouchEvent(MotionEvent event)

public boolean onInterceptTouchEvent (MotionEvent ev)

Added in API level 1

Implement this method to intercept all touch screen motion events. This allows you to watch events as they are dispatched to your children, and take ownership of the current gesture at any point.

Using this function takes some care, as it has a fairly complicated interaction with View.onTouchEvent(MotionEvent), and using it requires implementing that method as well as this one in the correct way. Events will be received in the following order:
  1. You will receive the down event here.
  2. The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal
  3. For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
  4. If you return true from here, you will not receive any following events: the target view will receive the same event but with the action ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.
Parameters
evThe motion event being dispatched down the hierarchy.
Returns
  • Return true to steal motion events from the children and have them dispatched to this ViewGroup through onTouchEvent(). The current target will receive an ACTION_CANCEL event, and no further messages will be delivered here

public boolean dispatchTouchEvent (MotionEvent ev)

Added in API level 1

Pass the touch screen motion event down to the target view, or this view if it is the target.

Parameters
evThe motion event to be dispatched.
Returns
  • True if the event was handled by the view, false otherwise.

public boolean onTouchEvent (MotionEvent event)

Added in API level 1

Implement this method to handle touch screen motion events.

If this method is used to detect click actions, it is recommended that the actions be performed by implementing and calling performClick(). This will ensure consistent system behavior, including:

  • obeying click sound preferences
  • dispatching OnClickListener calls
  • handling ACTION_CLICK when accessibility features are enabled

Parameters
eventThe motion event.
Returns
  • True if the event was handled, false otherwise.


2个关键类:View ViewGroup



一、概述
  1. View类有dispatchTouchEvent、onTouchEvent两个函数。ViewGroup集成自View,有dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三个函数。
  2. TouchEvent是由父视图向子视图传递的,在视图树上表现是根向叶子传递。
  3. TouchEvent会不断被传递,但只会被处理一次。



二、View对TouchEvent的处理流程
  • 父视图通过调用当前视图的dispatchTouchEvent函数将TouchEvent传递给当前视图
  • 当前视图判断自身是否注册了onTouchListener、是否Enabled、注册的onTouchListener是否返回True,如果这些条件全部满足,意味着TouchEvent被onTouchListener处理了。那么也就不需要调用当前视图的onTouchEvent函数了,直接返回True告诉父视图,”你传递给我的TouchEvent我已经处理了”。
  • 否则调用当前视图的onTouchEvent函数
     View中的dispatchTouchEvent函数
  1. public boolean dispatchTouchEvent(MotionEvent event) {  
  2.     if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
  3.             mOnTouchListener.onTouch(this, event)) {  
  4.         return true;  
  5.     }  
  6.     return onTouchEvent(event);  
  7. }  

三、ViewGroup对TouchEvent的处理流程
  • 同View一样,父视图会调用ViewGroup的dispatchTouchEvent函数,这是ViewGroup对TouchEvent的处理的起点
  • ViewGroup的dispatchTouchEvent函数相对于View中的dispatchTouchEvent函数来说复杂一点。因为它要额外做两件事,一是判断要不要截获TouchEvent,二是维护一个TouchEvent的目标视图。
  • 判断要不要截获TouchEvent
     解释一下doc里面的几点
  1. The down event will be handled either by a child of this viewgroup, or given to your own onTouchEvent() method to handle; this means  you should implement onTouchEvent() to return true, so you will  continue to see the rest of the gesture (instead of looking for  a parent view to handle it).  Also, by returning true from  onTouchEvent(), you will not receive any following  events in onInterceptTouchEvent() and all touch processing must  happen in onTouchEvent() like normal. 如果你在这里返回true,在onTouchEvent函数里也返回true,可以接收到手势的后续事件。这里的收到,是指onTouchEvent收到。这种情况下,onInterceptTouchEvent获取不到了。因为你在onTouchEvent里面对down event返回了true,表示你要处理这个手势,你也就成为了这个手势目标视图,那么这个手势的后续事件,view group将直接发送给你,而不再考虑分发给子视图,也就不存在要不要截获的问题,自然也就不会调用onInterceptTouchEvent,所以后续的手势onInterceptTouchEvent获取不到。
  2. For as long as you return false from this function, each following  event (up to and including the final up) will be delivered first here  and then to the target's onTouchEvent().如果你从这个函数返回false,那么后续的事件都会在这个函数里出现,然后分发给目标视图的onTouchEvent函数处理。

  1. ** 
  2.  * Implement this method to intercept all touch screen motion events.  This 
  3.  * allows you to watch events as they are dispatched to your children, and 
  4.  * take ownership of the current gesture at any point. 
  5.  * 
  6.  * <p>Using this function takes some care, as it has a fairly complicated 
  7.  * interaction with {@link View#onTouchEvent(MotionEvent) 
  8.  * View.onTouchEvent(MotionEvent)}, and using it requires implementing 
  9.  * that method as well as this one in the correct way.  Events will be 
  10.  * received in the following order: 
  11.  * 
  12.  * <ol> 
  13.  * <li> You will receive the down event here. 
  14.  * <li> The down event will be handled either by a child of this view 
  15.  * group, or given to your own onTouchEvent() method to handle; this means 
  16.  * you should implement onTouchEvent() to return true, so you will 
  17.  * continue to see the rest of the gesture (instead of looking for 
  18.  * a parent view to handle it).  Also, by returning true from 
  19.  * onTouchEvent(), you will not receive any following 
  20.  * events in onInterceptTouchEvent() and all touch processing must 
  21.  * happen in onTouchEvent() like normal. 
  22.  * <li> For as long as you return false from this function, each following 
  23.  * event (up to and including the final up) will be delivered first here 
  24.  * and then to the target's onTouchEvent(). 
  25.  * <li> If you return true from here, you will not receive any 
  26.  * following events: the target view will receive the same event but 
  27.  * with the action {@link MotionEvent#ACTION_CANCEL}, and all further 
  28.  * events will be delivered to your onTouchEvent() method and no longer 
  29.  * appear here. 
  30.  * </ol> 
  31.  * 
  32.  * @param ev The motion event being dispatched down the hierarchy. 
  33.  * @return Return true to steal motion events from the children and have 
  34.  * them dispatched to this ViewGroup through onTouchEvent(). 
  35.  * The current target will receive an ACTION_CANCEL event, and no further 
  36.  * messages will be delivered here. 
  37.  */  
  38. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  39.     return false;  

四、ViewGroup onInterceptTouchEvent接收到TouchEvent情况分析
    查看源码发现,Android4.0对ViewGroup的dispatchTouchEvent函数做了修改。Android4.0以上版本和以下版本onInterceptTouchEvent接收到TouchEvent情况是不同的。这里主要分析Android4.0以上版本onInterceptTouchEvent接收到TouchEvent情况。
    分析的主要内容有
  1. onInterceptTouchEvent接收TouchEvent受哪些因素影响
  2. onInterceptTouchEvent将接收到哪些类型的TouchEvent
    先看源码
    再说结论
  1. 一个手势是一个周期,下一个手势与上一个手势相同对待
  2. onInterceptTouchEvent总是能接受到down event
  3. 如果onInterceptTouchEvent在接收到down event时返回false的话,而子视图在dispatchTouchEvent中返回true的话,那么这个手势的后续事件都会被接收到
  4. 如果onInterceptTouchEvent在接收到down event时返回false的话,而子视图在dispatchTouchEvent中返回false的话,那么这个手势的后续事件不会被接收到
  5. 如果onInterceptTouchEvent在接收到down event时返回true的话,那么这个手势的后续事件不会被接收到
    进行验证
    验证3
package com.example.ligang.demo_autopullrefreshlistview;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.TextView;public class TestInterceptActivity extends Activity {    private final static String TAG = TestInterceptActivity.class.getSimpleName();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        MyViewGroup viewGroup = new MyViewGroup(this);        MyView view = new MyView(this);        view.setText("hello");        viewGroup.addView(view);        setContentView(viewGroup);    }    class MyViewGroup extends LinearLayout {        public MyViewGroup(Context context) {            super(context);        }        @Override        public boolean onInterceptTouchEvent(MotionEvent ev) {            switch (ev.getAction()) {                case MotionEvent.ACTION_DOWN:                    Log.e(TAG, "ACTION_DOWN");                    break;                case MotionEvent.ACTION_MOVE:                    Log.e(TAG, "ACTION_MOVE");                    break;                case MotionEvent.ACTION_UP:                    Log.e(TAG, "ACTION_UP");                    break;                case MotionEvent.ACTION_CANCEL:                    Log.e(TAG, "ACTION_CANCEL");                    break;                default:                    break;            }            return false;        }        @Override        public boolean onTouchEvent(MotionEvent event) {            return super.onTouchEvent(event);        }    }    class MyView extends TextView {        public MyView(Context context) {            super(context);        }        @Override        public boolean onTouchEvent(MotionEvent event) {            return true;        }    }}


    验证4
package com.example.ligang.demo_autopullrefreshlistview;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.TextView;public class TestInterceptActivity extends Activity {    private final static String TAG = TestInterceptActivity.class.getSimpleName();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        MyViewGroup viewGroup = new MyViewGroup(this);        MyView view = new MyView(this);        view.setText("hello");        viewGroup.addView(view);        setContentView(viewGroup);    }    class MyViewGroup extends LinearLayout {        public MyViewGroup(Context context) {            super(context);        }        @Override        public boolean onInterceptTouchEvent(MotionEvent ev) {            switch (ev.getAction()) {                case MotionEvent.ACTION_DOWN:                    Log.e(TAG, "ACTION_DOWN");                    break;                case MotionEvent.ACTION_MOVE:                    Log.e(TAG, "ACTION_MOVE");                    break;                case MotionEvent.ACTION_UP:                    Log.e(TAG, "ACTION_UP");                    break;                case MotionEvent.ACTION_CANCEL:                    Log.e(TAG, "ACTION_CANCEL");                    break;                default:                    break;            }            return false;        }        @Override        public boolean onTouchEvent(MotionEvent event) {            return super.onTouchEvent(event);        }    }    class MyView extends TextView {        public MyView(Context context) {            super(context);        }        @Override        public boolean onTouchEvent(MotionEvent event) {            return false;        }    }}


    验证5
package com.example.ligang.demo_autopullrefreshlistview;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.TextView;public class TestInterceptActivity extends Activity {    private final static String TAG = TestInterceptActivity.class.getSimpleName();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        MyViewGroup viewGroup = new MyViewGroup(this);        MyView view = new MyView(this);        view.setText("hello");        viewGroup.addView(view);        setContentView(viewGroup);    }    class MyViewGroup extends LinearLayout {        public MyViewGroup(Context context) {            super(context);        }        @Override        public boolean onInterceptTouchEvent(MotionEvent ev) {            switch (ev.getAction()) {                case MotionEvent.ACTION_DOWN:                    Log.e(TAG, "ACTION_DOWN");                    break;                case MotionEvent.ACTION_MOVE:                    Log.e(TAG, "ACTION_MOVE");                    break;                case MotionEvent.ACTION_UP:                    Log.e(TAG, "ACTION_UP");                    break;                case MotionEvent.ACTION_CANCEL:                    Log.e(TAG, "ACTION_CANCEL");                    break;                default:                    break;            }            return true;        }        @Override        public boolean onTouchEvent(MotionEvent event) {            return super.onTouchEvent(event);        }    }    class MyView extends TextView {        public MyView(Context context) {            super(context);        }        @Override        public boolean onTouchEvent(MotionEvent event) {            return false;        }    }}




0 0
原创粉丝点击