文档章节

android事件分发机制总结

亓斌哥哥
 亓斌哥哥
发布于 2014/10/08 20:49
字数 1106
阅读 956
收藏 19

Android事件分发机制

 

android 普通view(不包含ViewGroup)和activity中主要有一下两个方法处理事件:

public boolean dispatchTouchEvent(MotionEvent ev) // 分发事件
public boolean onTouchEvent(MotionEvent event)     // 处理事件

 

ViewGroup中还一个方法:

public boolean onInterceptTouchEvent(MotionEvent ev) // 拦截事件

 

1、activity中,顺序是:事件分发->事件处理,如果在事件分发时消费了某个事件(return true)则事件处理将不会接收到该事件。

 

public class MainActivity extends Activity {
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 事件分发
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_MOVE) {
 System.out.println("dispatchTouchEvent-->ACTION_MOVE");
return true; // 表示我消费了,不继续分发
}
return super.dispatchTouchEvent(ev);
}
// 处理事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("onTouchEvent-->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("onTouchEvent-->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("onTouchEvent-->ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}

 

以上代码的结果:

onTouchEvent-->ACTION_DOWN

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

onTouchEvent-->ACTION_UP

 

从结果上看:ACTION_MOVE并没有到onTouchEvent中,因为我们在dispatchTouchEvent判断,如果是ACTION_MOVEreturn true表示消耗掉该事件,事件就不会分发到onTouchEvent中,所有onTouchEvent只能接收到ACTION_DOWNACTION_UP事件。

 

2、普通view的事件分发

 

一个普通view的事件由dispatchTouchEvent分发事件,事件的顺序是ACTION_DOWNACTION_MOVEACTION_UP,如果有一个事件被消费掉,其他的事件不会执行到;分发事件由onTouch首先接收到,如果onTouch返回true了,表示消费掉了该事件,那么该viewclick事件将不会执行。

 

mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
  System.out.println("onTouch..."+event.getAction());
return true;  // 消费了该事件,下面的click事件不会执行
}
});
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 因为上面的onTouch把事件消费了,则这里执行不到
System.out.println("onClick...");
}
});

 

 

3、ViewGroup的事件分发:

ViewGroup的事件分发稍微麻烦点,以自定义的LinearLayout : MyLayout为例;

事件发生,首先由MyLayout的dispatchTouchEvent进行事件的分发
然后到MyLayout的onInterceptTouchEvent拦截事件
1、onInterceptTouchEvent如果return true表示拦截该事件,并在MyLayout中处理
剩下的事件,事件继续由MyLayout进行分发,分发机制同上面的view事件分发机制,但这次分发不会考虑分发给子view,也不会走onInterceptTouchEvent,因为系统已经知道
该套事件MyLayout已经拦截,所以直接在MyLayout中处理

2、如果MyLayoutonInterceptTouchEvent返回false(默认返回false[1]),表示不拦截事件,由MyLayout的子view(以Button为例)的dispatchTouchEvent开始分发事件,分发机制就是上面的view事件分发机制。

public class MyLayout extends LinearLayout {
	public MyLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public MyLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		System.out.println("dispatchTouchEvent");
		return super.dispatchTouchEvent(ev);
	}
	
	
	// 事件发生, 首先由MyLayout的dispatchTouchEvent进行事件的分发
	// 然后到MyLayout的onInterceptTouchEvent拦截事件
	// 如果return true表示拦截该事件,并在MyLayout中处理
	// 剩下的事件继续由MyLayout进行分发,这次分发不会考虑分发给
	// 子view,也不会走onInterceptTouchEvent,因为系统已经知道
	// 该套事件MyLayout已经拦截,所以直接在MyLayout中处理
	
	// 该demo的执行结果:
	// 第一套down、move、up :
	// dispatchTouchEvent
	// onInterceptTouchEvent
	// action_down...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_up...
	
	// 再一套:
	// dispatchTouchEvent
	// onInterceptTouchEvent
	// action_down...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_up...
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		System.out.println("onInterceptTouchEvent");
		if(ev.getAction() == MotionEvent.ACTION_DOWN) {
			return true;
		}
		return super.onInterceptTouchEvent(ev);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("action_down...");
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("action_up...");
			break;
		case MotionEvent.ACTION_MOVE:
			System.out.println("action_move...");
			break;
		}
		return true;
	}
}

执行的结果:

 第一套down、move、up :
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...
 
再一套:
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...

 

MyLinearLayout

public class MyLinearLayout extends LinearLayout{
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;  
// 这里返回true, 则拦截掉事件,不会再往子view传递,继续调用该view的dispachTouchEvent和onTouch
}
}

 

 

MainActivity:

public class MainActivity extends Activity {
private MyLinearLayout mLayout;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout = (MyLinearLayout) findViewById(R.id.layout);
mButton = (Button) findViewById(R.id.click);
mLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("layout touch " + event.getAction());
return false;
}
});
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 因为在MyLinearLayout中已经拦截了事件,所以这里不会输出
               System.out.println("button click...");
}
});
}
}

 

执行结果:

layout touch 0


注意[1] : ListViewonInterceptTouchEvent默认返回的是true,表示拦截了事件。所以在listView中的Button按照普通设置click的方法是不能点击的。


© 著作权归作者所有

共有 人打赏支持
亓斌哥哥

亓斌哥哥

粉丝 28
博文 34
码字总数 12346
作品 13
莱芜
程序员
私信 提问
加载中

评论(1)

宇宙执政
宇宙执政
写的真好,谢谢楼主
Android 机制篇 - 事件分发机制超详解(🔥🔥🔥🔥🔥🔥🔥🔥)

Android 虽然不是四大组件,但其并不比四大组件的地位低(涉及面的广度和深入甚至比四大组件还复杂🔥)。而View的核心知识点“事件分发机制”则是不少刚入门同学的拦路虎(1、项目中处处遇...

Pepsimaxin
07/12
0
0
安卓自定义View进阶-事件分发机制原理

安卓自定义View进阶-事件分发机制原理 之前讲解了很多与View绘图相关的知识,你可以在 安卓自定义View教程目录 中查看到这些文章,如果你理解了这些文章,那么至少2D绘图部分不是难题了,大部...

猴亮屏
05/22
0
0
Android Touch事件传递机制解析

没事逛论坛,无意间看到了一篇非常不错的帖子,转载如下: 开篇语:最近程序在做一个小效果,要用到touch,结果整得云里面雾里的,干脆就好好把android touch机制好好看了一下,呵呵。。 an...

长平狐
2012/10/09
2.1K
0
Android Hybrid开发:这是一份详细 & 全面的WebView学习攻略

前言 现在很多里都内置了Web网页(),比如说很多电商平台,淘宝、京东、聚划算等等,如下图 那么这种该如何实现呢?其实这是里一个叫组件实现 今天,我将献上一份全面 & 详细的 攻略,含具体...

Carson_Ho
06/19
0
0
(JVM)Java虚拟机:类加载的5个过程

前言 了解 类加载的过程,有利于在类初始化时进行一些功能操作 本文全面讲解类加载过程,希望你们会喜欢。 在接下来的日子,我会推出一系列讲解的文章,具体如下;感兴趣可持续关注Carson_Ho...

Carson_Ho
11/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

isEmpty和null的区别

isEmpty和null的区别: 1.一个是对象为空(IsNull),一个是值为空(IsEmpty) 2.IsNull指任务类型变量是否为空包括对象类型的变量。 IsNull函数: 功能:返回Boolean的值,指明表达是否不包...

DemonsI
13分钟前
0
0
Centos7 安装mysql与php

https://blog.csdn.net/qq_36431213/article/details/79576025 官网下载安装mysql-server 依次使用下面三个命令安装 wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.r......

Yao--靠自己
23分钟前
0
0
详解如何实现一个简单的 vuex

首先我们需要知道为何要使用 vuex。父子组件通信用 prop 和自定义事件可以搞定,简单的非父子组件通信用 bus(一个空的 Vue 实例)。那么使用 vuex 就是为了解决复杂的非父子组件通信。 仅仅...

嫣然丫丫丫
28分钟前
1
0
算法——RangePartitioner实现之reservoirSample

简介 reservoir的作用是:**在不知道文件总行数的情况下,如何从文件中随机的抽取一行?**即是说如果最后发现文字档共有N行,则每一行被抽取的概率均为1/N? 我们可以:定义取出的行号为cho...

freeli
30分钟前
1
0
Python安装及netcdf数据读写

一、在CentOS7系统上安装Python3 在anaconda官网下载(http://https://www.anaconda.com/download/#linux)(Anaconda指的是一个开源的Python发行版本,是Python的包管理器和环境管理器) 下...

voole
34分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部