博客
关于我
Android View事件分发机制理解
阅读量:400 次
发布时间:2019-03-05

本文共 6698 字,大约阅读时间需要 22 分钟。

  为了很好的理解事件分发机制,我们用一个自定义的RelativeLayout,里面装一个自定义的Button,然后分别MyRelativelayout重写里面的dispatchTouchEvent、onInterceptTouchEvent以及onTouchEvent方法,重写MyButton的onTouchEvent以及dispatchTouchEvent。(这里说明一下,因为RelativeLayout是继承ViewGroup的,所以它有拦截机制(onInterceptTouchEvent),但Button是继承是View的,所以没有这个方法),为了方便事件机制理解,这里demo只看ACTION_DOWN事件。

   

   首先都是返回父类的方法,看看返回结果:

   MyRelativeLayout.java

public class MyRelativeLayout extends RelativeLayout {    public MyRelativeLayout(Context context) {        super(context);    }    public MyRelativeLayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        if(event.getAction()==MotionEvent.ACTION_DOWN)            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===onTouchEvent");        return super.onTouchEvent(event);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if(ev.getAction()==MotionEvent.ACTION_DOWN)            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===onInterceptTouchEvent");        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if(ev.getAction()==MotionEvent.ACTION_DOWN)            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===dispatchTouchEvent");        return super.dispatchTouchEvent(ev);    }}

MyButton.java

public class MyButton extends Button {    public MyButton(Context context) {        super(context);    }    public MyButton(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public MyButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        if(event.getAction()==MotionEvent.ACTION_DOWN)            Log.d(MyConstants.VIEW_TAG,MyButton.class.getSimpleName()+"===onTouchEvent");        return super.onTouchEvent(event);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if(ev.getAction()==MotionEvent.ACTION_DOWN)            Log.d(MyConstants.VIEW_TAG,MyButton.class.getSimpleName()+"===dispatchTouchEvent");        return super.dispatchTouchEvent(ev);    }}

MainActivity调用如下:

private void testButton() {        MyRelativeLayout myRelativeLayout = findViewById(R.id.my_relative);        myRelativeLayout.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                if(event.getAction()==MotionEvent.ACTION_DOWN)                    Log.d(MyConstants.VIEW_TAG,"testButton myRelativeLayout====onTouch");                return false;            }        });        MyButton myButton = findViewById(R.id.my_button);        myButton.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                if(event.getAction()==MotionEvent.ACTION_DOWN)                    Log.d(MyConstants.VIEW_TAG,"testButton myButton====onTouch");                return false;            }        });    }

结果如下:

2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent

2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyButton===dispatchTouchEvent
2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: testButton myButton====onTouch
2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyButton===onTouchEvent

从这里可以分析出来,如果走父类默认的事件分发机制,则先走MyRelativeLayout的分发,拦截,然后给子类消费。

 

假设我们将上述MainActivity调用改为:

MyButton myButton = findViewById(R.id.my_button);        myButton.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                if(event.getAction()==MotionEvent.ACTION_DOWN)                    Log.d(MyConstants.VIEW_TAG,"testButton myButton====onTouch");                return true;            }        });

则会返回结果如下:

2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent

2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: MyButton===dispatchTouchEvent
2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: testButton myButton====onTouch

事件不再回到MyButton的onTouch

假设我们在MyRelativeLayout拦截这个事件:

@Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if(ev.getAction()==MotionEvent.ACTION_DOWN)            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===onInterceptTouchEvent");        return true;//super.onInterceptTouchEvent(ev)    }

则会返回如下结果:

2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent

2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: testButton myRelativeLayout====onTouch
2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onTouchEvent

我们可以看到MyButton不会有任何事件响应,事件被我们MyRelativeLayout消费掉了。

 

我们再假设在MyRelativeLayout不再往下分发这个事件:

@Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if(ev.getAction()==MotionEvent.ACTION_DOWN)            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===dispatchTouchEvent");        return false;//super.dispatchTouchEvent(ev)    }

则会返回如下结果:

2021-04-05 10:54:08.848 8922-8922/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent

我们发现事件到dispathTouchEvent之后,就不再放下传递了。

 

同理,我们如果放开MyRelativeLayout的事件分发和拦截,然后修改MyButton的事件分发为false:

则会出现如下结果:

2021-04-05 10:56:03.519 9061-9061/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent

2021-04-05 10:56:03.519 9061-9061/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:56:03.519 9061-9061/com.jxd.studyone D/VIEW_TAG: MyButton===dispatchTouchEvent

总结:

1.事件分发是从外层向内层分发

2.从Activity向ViewGroup,再向view进行分发。

3.事件如果不分发,或者被拦截,则子view不会再接收到相应的事件。

至此,我相信各位安卓开发的同学已经知道事件分发机制的来龙去脉了。

 

转载地址:http://dfbzz.baihongyu.com/

你可能感兴趣的文章
mysql 常见问题
查看>>
MYSQL 幻读(Phantom Problem)不可重复读
查看>>
mysql 往字段后面加字符串
查看>>
mysql 快照读 幻读_innodb当前读 与 快照读 and rr级别是否真正避免了幻读
查看>>
MySQL 快速创建千万级测试数据
查看>>
mysql 快速自增假数据, 新增假数据,mysql自增假数据
查看>>
MySql 手动执行主从备份
查看>>
Mysql 批量修改四种方式效率对比(一)
查看>>
Mysql 报错 Field 'id' doesn't have a default value
查看>>
MySQL 报错:Duplicate entry 'xxx' for key 'UNIQ_XXXX'
查看>>
Mysql 拼接多个字段作为查询条件查询方法
查看>>
mysql 排序id_mysql如何按特定id排序
查看>>
Mysql 提示:Communication link failure
查看>>
mysql 插入是否成功_PDO mysql:如何知道插入是否成功
查看>>
Mysql 数据库InnoDB存储引擎中主要组件的刷新清理条件:脏页、RedoLog重做日志、Insert Buffer或ChangeBuffer、Undo Log
查看>>
mysql 数据库中 count(*),count(1),count(列名)区别和效率问题
查看>>
mysql 数据库备份及ibdata1的瘦身
查看>>
MySQL 数据库备份种类以及常用备份工具汇总
查看>>
mysql 数据库存储引擎怎么选择?快来看看性能测试吧
查看>>
MySQL 数据库操作指南:学习如何使用 Python 进行增删改查操作
查看>>