Android 事件分发机制

简介

  • Android 事件分发机制是Android UI非常重要的一个机制,处理UI逻辑的时候必须要非常清楚事件分发的顺序。 这里以TouchEvent事件来举例子。
  • TouchEvent事件从Activity开始分发然后分发到布局文件的各个View中。

Activity,View,ViewGroup中TouchEvent的处理方法

  1. Activity 中TouchEvent的处理方法
    dispatchTouchEvent(MotionEvent ev)
    onTouchEvent(MotionEvent event)
  2. ViewGroup中TouchEvent的处理方法
    dispatchTouchEvent(MotionEvent ev)
    onInterceptTouchEvent(MotionEvent ev)—-默认返回false
    onTouchEvent(MotionEvent event)
  3. View中TouchEvent的处理方法
    dispatchTouchEvent(MotionEvent ev)
    onTouchEvent(MotionEvent event)

那么TouchEvent 就在以上的几个类中分发了,根据不同方法的返回值作不同的分发处理。
返回true-消费这个事件。
返回false-分发这个事件。

Activity,ViewGroup,View中TouchEvent分发示例

  1. 一个Activity,该Activity包含一个布局文件,该布局文件包含两个自定义的View,第一个view继承LinearLayout,第二个view继承View。
  2. 在这里每一个view的dispatchTouchEvent和onTouchEvent方法都必须调用父类的dispatchTouchEvent和onTouchEvent的方法,这样事件才会一层一层的分发下去,如果不重写,dispatchTouchEvent或者onTouchEvent直接返回true或者false,事件到当前view就不会再分发给子view。

布局关系图

这里写图片描述

实现Activity 中事件处理的方法。

public class TestEventActivity extends AppCompatActivity {
    static final String TAG = "TestEvent-"+TestEventActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_event);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar)
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG,"onTouchEvent");
        return super.onTouchEvent(event);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d(TAG,"dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }
}

实现ViewGroup 中事件处理的方法

public class FirstView extends LinearLayout {
    static final String TAG = "TestEvent-"+FirstView.class.getSimpleName();
    public FirstView(Context context) {
        super(context);
    }
    public FirstView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d(TAG,"dispatchTouchEvent false");
        return super.dispatchTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d(TAG,"onInterceptTouchEvent false");
        return super.onInterceptTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG,"onTouchEvent false");
        return super.onTouchEvent(event);
    }
}

实现View 中事件处理的方法

public class SecondView extends View {
    static final String TAG = "TestEvent-"+ThirdView.class.getSimpleName();
    public ThirdView(Context context) {
        super(context);
    }
    public ThirdView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d(TAG,"dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG,"onTouchEvent");
        return super.onTouchEvent(event);
    }
}

默认情况下TouchEvent 事件的分发流程.所有的事件处理方法都返回false,

D/TestEvent-TestEventActivity: dispatchTouchEvent  ACTION_DOWN
D/TestEvent-FirstView: dispatchTouchEvent  ACTION_DOWN
D/TestEvent-FirstView: onInterceptTouchEvent  ACTION_DOWN
D/TestEvent-SecondView: dispatchTouchEvent  ACTION_DOWN
D/TestEvent-SecondView: onTouchEvent  ACTION_DOWN
D/TestEvent-FirstView: onTouchEvent  ACTION_DOWN
D/TestEvent-TestEventActivity: onTouchEvent  ACTION_DOWN
D/TestEvent-TestEventActivity: dispatchTouchEvent  ACTION_MOVE
D/TestEvent-TestEventActivity: onTouchEvent  ACTION_MOVE
D/TestEvent-TestEventActivity: dispatchTouchEvent  ACTION_UP
D/TestEvent-TestEventActivity: onTouchEvent  ACTION_UP

ACTION_DOWN事件通过dispatchTouchEvent传递顺序

这里写图片描述

ACTION_DOWN事件通过onTouchEvent传递顺序

这里写图片描述

  1. ACTION_DOWN事件通过dispatchTouchEvent 的分发顺序是从Activity开始的,通过onTouchEvent的分发顺序是从SecondView开始的。
  2. 因为FirstView和SecondView事件处理方法都返回false,后续的ACTION_MOVE,ACTION_UP事件也不会再分发下去,到Activity就终止了。

从上面的结论可以看出,默认情况下系统先按照UI布局的结构从外到里通过调用各个组件的dispatchTouchEvent方法来传递事件,然后再从里到外通过调用各个组件的onTouchEvent方法传递事件,这样一个循环的模式。在调用的过程当中,只要有方法返回true就表示事件被消费了,事件将不会再分发下去。

Activity的dispatchTouchEvent 返回true

*ACTION_DOWN*事件分发顺序还是和上面两个图一样,但是后续的*ACTION_MOVE,ACTION_UP*只会在Activity消费了。

FirstView的dispatchTouchEvent或者onTouchEvent方法返回true

dispatchTouchEvent传递*ACTION_DOWN*事件还是和上图一样。但是onTouchEvent传递*ACTION_DOWN*事件就不一样了,到FirstView就不会再往下传递了,dispatchTouchEvent方法和onTouchEvent传递*ACTION_MOVE,ACTION_UP*也一样,到了FirstView就会被拦截消费。

SecondView的dispatchTouchEvent或者onTouchEvent方法返回true

dispatchTouchEvent传递*ACTION_DOWN,ACTION_MOVE,ACTION_UP*事件还是和上图一样。但是onTouchEvent传递*ACTION_DOWN,ACTION_MOVE,ACTION_UP*事件就不一样了,到SecondView就不会再往下传递了。
#前言 之前笔者其实已经写过事件分发机制的文章:[快速理解android事件传递拦截机制概念](http://blog.csdn.net/double2hao/article/details/51541061) 但是,现在看来其实更像是一篇知识概括,多出可能未讲清楚,于是打算重写事件分发,用一篇文章大致讲清楚。 首先,形式上笔者最先思考的是使用源码,此者能从原理上讲解分发机制,比起侃侃而谈好得多。但是源码的复杂往往会让新手产生畏惧难以理解,于是笔者最终还是打算使用实例log来让读者理解android事件分发。 #重要函数 笔者此次主要提及最常用的几个函数: (其间区别看源码很容易理解,此处直接给上结果) **onClick():**这个函数是是View提供给我们的OnClickListener这个接口的函数,在这里可以自定义对点击事件的处理逻辑。会在onTouchEvent()进行调用。 **onTouch():**这个函数是View提供给我们的OnTouchListener这个接口的函数,在这里面可以自定义对触摸事件的处理逻辑。 **onTouchEvent():**这个函数是view内部的触摸事件的处理方式,其间包括获取焦点,调用onClick()等等。 **dispatchTouchEvent():**这个是View的事件分发函数,在ViewGroup进行重写。在View其间会调用onTouchEvent(),在ViewGroup其间会调用onInterceptTouchEvent()和onTouchEvent()。 **onInterceptTouchEvent():**这个函数是事件拦截函数,是ViewGroup才有的函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值