【转】Android TouchEvent事件传递机制
| Activity类: | Activity | dispatchTouchEvent(); onTouchEvent(); |
| View容器(ViewGroup的子类): | FrameLayout、LinearLayout…… ListView、ScrollVIew…… |
dispatchTouchEvent(); onInterceptTouchEvent(); onTouchEvent(); |
| View控件(非ViewGroup子类): | Button、TextView、EditText…… | dispatchTouchEvent(); onTouchEvent(); |
| dispatchTouchEvent() | 用来分派事件。 其中调用了onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法 |
| onInterceptTouchEvent() | 用来拦截事件。 ViewGroup类中的源码实现就是{return false;}表示不拦截该事件, 事件将向下传递(传递给其子View); 若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递, 事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法 |
| onTouchEvent() | 用来处理事件。 返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View); 返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理 |
- 按常理,领导都会把任务向下分派,一旦下面的人把事情做不好,就不会再把后续的任务交给下面的人来做了,只能自己亲自做,如果自己也做不了,就只能告诉上级不能完成任务,上级又会重复他的过程。
- 另外,领导都有权利拦截任务,对下级隐瞒该任务,而直接自己去做,如果做不成,也只能向上级报告不能完成任务。
【1】TextView的clickable属性默认是false,所以TextView的onTouchEvent()方法默认返回false,程序输出如下:
事件传递示意图:
一系列的传递流程都是dispatchTouchEvent()方法来控制的,如果不人为地干预,事件将由上自下依次传递(因为默认是返回false不会
拦截的),传递到最底层的View,就由它的onTouchEvent()方法来处理事件,若处理成功返回true,若处理失败返回false,事件依次
向上传递,每个View都调用自己的onTouchEvent()方法来处理事件,若处理成功就终止传递,若处理失败就继续向上传递。
外,dispatchTouchEvent()方法中还有“记忆”的功能,如果第一次事件向下传递到某View,它把事件继续传递交给它的子View,它
会记录该事件是否被它下面的View给处理成功了,(怎么能知道呢?如果该事件会再次被向上传递到我这里来由我的onTouchEvent()来处理,那
就说明下面的View都没能成功处理该事件);当第二次事件向下传递到该View,该View的dispatchTouchEvent()方法机会判断,
若上次的事件由下面的view成功处理了,那么这次的事件就继续交给下面的来处理,若上次的事件没有被下面的处理成功,那么这次的事件就不会向下传递了,
该View直接调用自己的onTouchEvent()方法来处理该事件。
忆”功能的信息只在一系列事件完成之前有效,如从ACTION_DOWN事件开始,直到后续事件ACTION_MOVE,ACTION_UP结束后,“记
忆”的信息就会清除。也就是说如果某View处理ACTION_DOWN事件失败了(onTouchEvent()返回false),那么后续的
ACTION_MOVE,ACTION_UP等事件就不会再传递到该View了,由其父View自己来处理。在下一次发生ACTION_DOWN事件的时
候,还是会传递到该View的。
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean bo = false;
Log.d("d", "【总统】任务<" + Util.actionToString(ev.getAction()) + "> : 下面都解决不了,下次再也不能靠你们了,哼…只能自己尝试一下啦。能解决?" + bo);
return bo;
}
}
public class MyFrameLayout extends FrameLayout
{
public MyFrameLayout(Context context, AttributeSet attrs){
super(context, attrs);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");
return super.dispatchTouchEvent(ev);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean bo = false;
Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);
return bo;
} @Override
public boolean onTouchEvent(MotionEvent ev) {
boolean bo = false;
Log.d("d", "【省长】任务<" + Util.actionToString(ev.getAction()) + "> : 市长是个废物,下次再也不找你了,我自己来尝试一下。能解决?" + bo);
return bo;
}
}
public class MyLinearLayout extends LinearLayout{
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean bo = false;
Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 拦截吗?" + bo);
return bo;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean bo = false;
Log.d("d", "【市长】任务<" + Util.actionToString(ev.getAction()) + "> : 农民真没用,下次再也不找你了,我自己来尝试一下。能解决?" + bo);
return bo;
}
}
public class MyTextView extends TextView
{
public MyTextView(Context context, AttributeSet attrs){
super(context, attrs);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev){
Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 需要分派,我下面没人了,怎么办?自己干吧");
return super.dispatchTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent ev){
boolean bo = true;
Log.d("d", "【农民】任务<" + Util.actionToString(ev.getAction()) + "> : 自己动手,埋头苦干。能解决?" + bo);
return bo;
}
}
原文地址:http://blog.csdn.net/morgan_xww/article/details/9372285
public class MainActivity extends Activity implements OnTouchListener {
private ImageView img;
private int lastX, lastY;
private int screenWidth, screenHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.img);
// 获取屏幕的宽和高
DisplayMetrics dm = getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
System.out.println("screenWidth-->>" + screenWidth
+ " screenHeight-->>" + screenHeight);
img.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("这是ImageView的onTouch");
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
/**
* 如果这里返回true 或者让ImageView
* 的android:onClick设置成true(表示down时间处理成功了)
* 在结合时间传递机制就知道为什么了Down-->>move-->>up
*/
return false;
case MotionEvent.ACTION_MOVE:
int dx = (int) (event.getRawX() - lastX);
int dy = (int) (event.getRawY() - lastY);
int left = v.getLeft() + dx;
int top = v.getTop() + dy;
int right = v.getRight() + dx;
int bottom = v.getBottom() + dy;
if (left <= 0) {
// 到达父View的左边界
left = 0;
right = left + v.getWidth();
}
if (right >= screenWidth) {
right = screenWidth;
left = right - v.getWidth();
}
if (top <= 0) {
top = 0;
bottom = top + v.getHeight();
}
if (bottom >= screenHeight) {
bottom = screenHeight;
top = bottom - v.getHeight();
}
v.layout(left, top, right, bottom);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
case MotionEvent.ACTION_UP:
System.out.println("释放后的位置-->>event.getX():" + event.getX()
+ " event.getY():" + event.getY()
+ " event.getRawX():" + event.getRawX()
+ " event.getRawY():" + event.getRawY());
break;
default:
break;
}
return false;
}
});
findViewById(R.id.btn).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("这是Button的onTouch");
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out
.println("ACTION_DOWNACTION_DOWNACTION_DOWNACTION_DOWNACTION_DOWN");
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
System.out.println("MOVEMOVE");
int dx = (int) (event.getRawX() - lastX);
int dy = (int) (event.getRawY() - lastY);
int left = v.getLeft() + dx;
int top = v.getTop() + dy;
int right = v.getRight() + dx;
int bottom = v.getBottom() + dy;
if (left <= 0) {
// 到达父View的左边界
left = 0;
right = left + v.getWidth();
}
if (right >= screenWidth) {
right = screenWidth;
left = right - v.getWidth();
}
if (top <= 0) {
top = 0;
bottom = top + v.getHeight();
}
if (bottom >= screenHeight) {
bottom = screenHeight;
top = bottom - v.getHeight();
}
v.layout(left, top, right, bottom);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
System.out.println("释放后的位置-->>event.getX():" + event.getX()
+ " event.getY():" + event.getY()
+ " event.getRawX():" + event.getRawX()
+ " event.getRawY():" + event.getRawY());
break;
default:
break;
}
return false;
}
});
}
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("这是Activity的onTouch");
return false;
}
}
activity_main.xml
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity" > <ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="图片"
android:focusable="true"
android:focusableInTouchMode="true"
android:src="@drawable/ic_launcher" >
</ImageView> <Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拖动试一试" /> </LinearLayout>
【转】Android TouchEvent事件传递机制的更多相关文章
- Android TouchEvent事件传递机制
本文转载自:http://blog.csdn.net/morgan_xww/article/details/9372285 跟touch事件相关的3个方法: public boolean dispat ...
- Android touch 事件传递机制
前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事 ...
- Android 的事件传递机制,详解
Android 的事件传递机制,详解 前两天和一个朋友聊天的时候.然后说到事件传递机制.然后让我说的时候,忽然发现说的不是非常清楚,事实上Android 的事件传递机制也是知道一些,可是感觉自己知道的 ...
- Android Touch事件传递机制 二:单纯的(伪生命周期)
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android Touch事件传递机制 一: OnTouch,OnItemClick(监听器),dispatchTouchEvent(伪生命周期)
ViewGroup View Activity dispatchTouchEvent 有 有 有 onInterceptTouchEvent 有 无 无 onTouchEvent 有 有 有 例 ...
- Android Touch事件传递机制通俗讲解
在讲正题之前我们讲一段有关任务传递的小故事,抛砖迎玉下: 话说一家软件公司,来一个任务,分派给了开发经理去完成: 开发经理拿到,看了一下,感觉好简单,于是 开发经理:分派给了开发组长 开发组长:分派给 ...
- Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android Touch事件传递机制引发的血案
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38942135 关于Android Touch事件传递机制我之前也写过两篇文章,自觉得对Tou ...
- Android触摸事件传递机制
简单梳理一下Android触摸事件传递机制的知识点. 一.View与ViewGroup的关系 View和ViewGroup二者的继承关系如下图所示: View是Android中最基本的一种UI组件,它 ...
随机推荐
- Android如何获取系统高度、标题栏和状态栏高度
在android应用中,有时需要计算个View的位置,导致需要计算状态栏高度,标题栏高度等信息.为以后方便,在此做个简单记录. 晒代码前先了解一下android屏幕区域的划分,如下图(该图引用自此文h ...
- aspose调用打印机打印文档
aspose很不错的插件,功能非常强大,用到了其中的aspose.word. 如何生成word文档,点击. 下面说说如何如何通过打印机打印文档. aspose提供了一个print方法,通过该方法可以直 ...
- Search in Rotated Sorted Array II
Question: Follow up for "Search in Rotated Sorted Array":What if duplicates are allowed? W ...
- Heritrix源码分析(十) Heritrix中的Http Status Code(Http状态码)(转)
本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/649737 本博客已迁移到本人独立博客: http://www.yun5u ...
- RabbitMQ链接不上异常
链接代码 项目启动报的异常 本地main方法链接报的异常 网上查询原因 问题说明及解决方案: 网上原因很多,最终原因都是连接不到数据库造成的. 1.查看防火墙 2.tomcat端口是否屏蔽 3.查看连 ...
- 集合框架null与size=0
被QA人员一眼指出来的问题,唉,好丢人 上栗子
- Mysql 不同版本 说明
Mysql 的官网下载地址: http://dev.mysql.com/downloads/ 在这个下载界面会有几个版本的选择. 1. MySQL Community Server 社区版本,免费,但 ...
- appdata文件夹有什么用途?C盘appdata可以删除吗?
在内存紧张的时候,我们都会选择删除一些无关紧要的大文件来释放内存,有不少网友发现在系统C盘下有一个appdata文件夹,而且体积挺大的,不知道能不能删除,针对此问题,本文就为大家介绍appdata文件 ...
- Android布局文件夹引起的问题
Android 运行到setContentView(R.layout.splash); 总是出现如下的错误: java.lang.RuntimeException: Unable to start a ...
- 使用python三方库xlrd解析excel数据
excel是平常用的比较多的一种数据格式,而在自动化测试过程中,解析其数据以供脚本使用就是一个重要的工作,幸好已有现存的三方库供使用,而不必重新造轮子. 一.安装xlrd模块 到python官网下载h ...