android触发事件传递机制

一 事件传递的三个阶段
1 分发(Dispatch):
事件的分发对应着dispatchTouchEvent方法,在Android系统中,所有的触摸事件的分发都是由改方法分发。

public booleandispatchTouchEvent(MotionEvent event) {..}

说明:在这个方法中,当前视图将根据返回值决定是否把这个事件继续传给子视图,如果返回true当前视图会直接消费掉该事件,不再分发给其子视图;如果返回super.dispatchTouchEvent(event) ,当前视图会把该事件分发给其子视图。如果当前视图是ViewGroup或其子类的话,还要调用onInterceptTouchEvent方法判断该事件是否被拦截。
2 拦截(Intercept):
事件的拦截,对应如下的方法:

public booleanonInterceptTouchEvent(MotionEvent ev) {...}

说明:这个方法只有在ViewGroup及其子类中有,它们通过返回值来判断是否拦截当前事件,如果返回true会拦截当前事件,不再分发给它们的子视图,同时会调用onTouchEvent消费该事件;如果返回false或super.onInterceptTouchEvent,那么它们会把当前事件分发给它们的子视图。
3 消费:
事件的消费,对应如下的方法:

public booleanonTouchEvent(MotionEvent ev) {...}

说明:该方法返回true则表示当前视图处理相应的事件,事件不会向上传递给父视图;返回false则表示当前视图不处理相应的事件,会把这个事件向上传递给父视图onTouchEvent方法进行处理。
Android系统中有事件传递能力的类有:
Activity:有dispatchTouchEvent、onTouchEvent两个方法。
ViewGroup:有dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent三个方法。
View:有dispatchTouchEvent、onTouchEvent两个方法。如下:
二 View事件传递
1 自定义TextView

public class MyTextView extends TextView {
    public static final String TAG = MyTextView.class.getSimpleName() + "======> ";
    public MyTextView(Context context) {
        super(context);
    }
    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"dispatchTouchEvent->ACTION_DOWN ");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"dispatchTouchEvent->ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"dispatchTouchEvent->ACTION_UP ");
                break;
        }
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"onTouchEvent->ACTION_DOWN ");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"onTouchEvent->ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"onTouchEvent->ACTION_UP ");
                break;
        }
        return super.onTouchEvent(event);
    }
}

2布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.eric.project.MainActivity">
    <com.eric.project.event.MyTextView
        android:id="@+id/txt_eventView"
        android:layout_centerInParent="true"
        android:textSize="36sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="View 事件传递" />
</RelativeLayout>

3 Activity代码:

public class MainActivity extends AppCompatActivity {
    public static final String TAG = MainActivity.class.getSimpleName() + "======> ";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView  txt_eventView  = (TextView) findViewById(R.id.txt_eventView);
        txt_eventView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG,"      onClick        ");
            }
        });
        //如果不设置触摸监听不会触发onTouchEvent方法
        txt_eventView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        Log.e(TAG,"    onTouch->ACTION_DOWN ");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.e(TAG,"    onTouch->ACTION_MOVE ");
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.e(TAG,"     onTouch->ACTION_UP ");
                        break;
                }
                return false;
            }
        });
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"dispatchTouchEvent->ACTION_DOWN ");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"dispatchTouchEvent->ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"dispatchTouchEvent->ACTION_UP ");
                break;
        }
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"onTouchEvent->ACTION_DOWN ");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"onTouchEvent->ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"onTouchEvent->ACTION_UP ");
                break;
        }
        return super.onTouchEvent(event);
    }
}
4 打印结果如下:
01-31 05:09:36.158 14865-14865/com.eric.project E/MainActivity======>: dispatchTouchEvent->ACTION_DOWN
01-31 05:09:36.158 14865-14865/com.eric.project E/MyTextView======>: dispatchTouchEvent->ACTION_DOWN
01-31 05:09:36.159 14865-14865/com.eric.project E/MainActivity======>: onTouch->ACTION_DOWN
01-31 05:09:36.159 14865-14865/com.eric.project E/MyTextView======>: onTouchEvent->ACTION_DOWN
01-31 05:09:36.254 14865-14865/com.eric.project E/MainActivity======>: dispatchTouchEvent->ACTION_UP
01-31 05:09:36.254 14865-14865/com.eric.project E/MyTextView======>: dispatchTouchEvent->ACTION_UP
01-31 05:09:36.254 14865-14865/com.eric.project E/MainActivity======>: onTouch->ACTION_UP
01-31 05:09:36.254 14865-14865/com.eric.project E/MyTextView======>: onTouchEvent->ACTION_UP
01-31 05:09:36.257 14865-14865/com.eric.project E/MainActivity======>: onClick

从上面得出如下结论:
(1)触摸事件的传递流程是从dispatchTouchEvent开始,如果不进行干预(即返回super.dispatchTouchEvent(ev)),则事件将会依照潜逃层次从外层向内层传递,到达最底层的View时,就由它的onTouchEvent方法进行处理,该方法如果能够消费该事件,就会返回true,如果处理不了,就返回false,这时会重新向外层传递,并由外层View的onTouchEvent方法进行处理,以此类推。
(2)如果事件在向内层传递的过程中人为干预了,时间函数返回true,则会导致事件提前被消费掉,内层的View不能收到事件。
(3)如果最内层的View能够接受到事件,那么它先执行的是onTouch方法,然后才执行onClick方法。如果onTouch返回true,则事件不会继续传递,最后也不会调用onClick方法;如果返回super.onTouch或false,事件会继续传递。流程图如下:


三 ViewGroup事件传递
1 自定义ViewGroup

public class MyViewGroup extends LinearLayout {
    public static final String TAG = MyViewGroup.class.getSimpleName() + "======> ";
    public MyViewGroup(Context context) {
        super(context);
    }
    public MyViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"dispatchTouchEvent->ACTION_DOWN ");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"dispatchTouchEvent->ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"dispatchTouchEvent->ACTION_UP ");
                break;
        }
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"onTouchEvent->ACTION_DOWN ");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"onTouchEvent->ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"onTouchEvent->ACTION_UP ");
                break;
        }
        return super.onTouchEvent(event);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"onInterceptTouchEvent->ACTION_DOWN ");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"onInterceptTouchEvent->ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"onInterceptTouchEvent->ACTION_UP ");
                break;
        }
        return super.onInterceptTouchEvent(event);
    }
}

2 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<com.eric.project.event.MyViewGroup
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context="com.eric.project.MainActivity">
    <com.eric.project.event.MyTextView
        android:id="@+id/txt_eventView"
        android:layout_centerInParent="true"
        android:textSize="36sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="View 事件传递" />
</com.eric.project.event.MyViewGroup>

4 打印日志:

02-01 15:49:55.721 23305-23305/com.eric.project E/MainActivity======>: dispatchTouchEvent->ACTION_DOWN
02-01 15:49:55.722 23305-23305/com.eric.project E/MyViewGroup======>: dispatchTouchEvent->ACTION_DOWN
02-01 15:49:55.722 23305-23305/com.eric.project E/MyViewGroup======>: onInterceptTouchEvent->ACTION_DOWN
02-01 15:49:55.722 23305-23305/com.eric.project E/MyTextView======>: dispatchTouchEvent->ACTION_DOWN
02-01 15:49:55.722 23305-23305/com.eric.project E/MainActivity======>: onTouch->ACTION_DOWN
02-01 15:49:55.722 23305-23305/com.eric.project E/MyTextView======>: onTouchEvent->ACTION_DOWN
02-01 15:49:55.745 23305-23305/com.eric.project E/MainActivity======>: dispatchTouchEvent->ACTION_MOVE
02-01 15:49:55.745 23305-23305/com.eric.project E/MyViewGroup======>: dispatchTouchEvent->ACTION_MOVE
02-01 15:49:55.745 23305-23305/com.eric.project E/MyViewGroup======>: onInterceptTouchEvent->ACTION_MOVE
02-01 15:49:55.745 23305-23305/com.eric.project E/MyTextView======>: dispatchTouchEvent->ACTION_MOVE
02-01 15:49:55.745 23305-23305/com.eric.project E/MainActivity======>: onTouch->ACTION_MOVE
02-01 15:49:55.745 23305-23305/com.eric.project E/MyTextView======>: onTouchEvent->ACTION_MOVE
02-01 15:49:55.746 23305-23305/com.eric.project E/MainActivity======>: dispatchTouchEvent->ACTION_UP
02-01 15:49:55.746 23305-23305/com.eric.project E/MyViewGroup======>: dispatchTouchEvent->ACTION_UP
02-01 15:49:55.746 23305-23305/com.eric.project E/MyViewGroup======>: onInterceptTouchEvent->ACTION_UP
02-01 15:49:55.746 23305-23305/com.eric.project E/MyTextView======>: dispatchTouchEvent->ACTION_UP
02-01 15:49:55.746 23305-23305/com.eric.project E/MainActivity======>: onTouch->ACTION_UP
02-01 15:49:55.746 23305-23305/com.eric.project E/MyTextView======>: onTouchEvent->ACTION_UP
02-01 15:49:55.747 23305-23305/com.eric.project E/MainActivity======>: onClick
从上面得出如下结论:
(1)触摸事件传递的顺序Activity到ViewGroup,再传递给ViewGroup的子类View。
(2)事件传递的过程,ViewGroup调用 onInterceptTouchEvent方法判断事件是否被拦截,如果 onInterceptTouchEvent返回true,事件被拦截,不会再传递给其子View,否则会继续传递。
(3)View接收到事件,由onTouchEvent方法进行处理,View能够处理,事件没有上传给ViewGroup。
流程图如下:

四 事件传递总结:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值