Touch事件的传递机制

本文主要从源代码的角度讲解view以及viewgroup的事件传递机制。

ViewGroup的dispatchTouchEvent方法:

Private TouchTarget firstTouchTarget;

Public Boolean dispatchTouchEvent(MotionEvent ev){

先进行安全检查,看看当前window有没有遮挡,如果没有继续

if(action==ACTION_DOWN){

清理上次的TouchTargets的状态,避免程序切换和ANR的时候会抛出ACTION_UP和ACTION_CANCEL事件对这个方法的影响,并对firstTouchTarget置空;

}

boolean intercept;

//是down事件或者有代理的情况下就判断要不要拦截

if(action==ACTION_DOWN||firstTouchTarget!=null){

//这儿判断一下子类是不是调过自己的requestDisallowInterceptTouchEvent()方法,如果调过,就不拦截事件了,没掉过,就看onInterceptTouchEvent()方法的。

if(disallow_intercept!=true){

intercept = onInterceptTouchEvent(ev);

}else{

intercept= false;

}

}else{

//不是初始的down事件,而且firstTouchTarget为空,才会走到这儿,1.没有子view 2.子view在down的时候没有消耗事件firstTouchTarget就为空了后续的move,up事件时,才会走到这儿

Intercept=true;

}

TouchTarget touchTarget=null;

boolean cancel=(action==ACTION_CANCEL);

If(!cancel&&!intercept){

//多点触控会添加多个TouchTarget。

If(action==ACTION_DOWN||actionMask==ACTION_POINTER_DOWN||actionMask==ACTION_HOVER_MOVE){

If(touchTarget==null&&childCount!=0){

//找一个子view进行TouchTarget代理设置,多从后往前搜索

for(int i=childCount-1;i>0;i--){

if(!child.contains(x,y)){

continue;

}

touchTarget=getTouchTarget(child);

If(touchTarget!=null){

break;

}

if( dispatchTransformdTouchEvent(ev,false,touchTarget.child,idbits)){

//这个方法也会给firstTouchTarget赋值

touchTarget=addTouchTarget(child);

}

}

If(touchTarget==null&&firstTouchTarget!=null){

没有找到子view,就让touchTarget变成firstTouchTarget的next,即最近的一个TouchTarget。(如果只有一个的话,首尾是相接的。)

}

}

}

}

boolean handle=false;

If(firstTouchTarget==null){

//对自己的touch事件进行处理

If( dispatchTransformdTouchEvent(ev,false,null,idbits)){

handle=true;

}

}else{

//循环的对每个子view进行touch事件的传递,一般就一个,多点触控的时候可能有多个,但只要有一个子view的dispatchTouchEvent返回的是true,则父类的dispatchTouchEvent就返回true。

TouchTarget target=firstTouchTarget;

While(tagert!=null){

//在down事件时上面给touchTarget赋值的时候已经调用了dispatchTransformdTouchEvent方法,这儿排除掉,避免重复。

If(target==touchTarget){

handle=true;

}

if( dispatchTransformdTouchEvent(ev,false,target.child,idbits)){

handle=true;

}

target=target.next;

}

}

If(cancel||action=ACTION_UP||action==ACTION_HOVER_MOVE){

一次触摸事件完成,状态重置。

}else if(action==ACTION_POINTER_UP{

多点触控的,从touchTarget链里删除离开屏幕的那个点。

}

return handle;

}

---------------------------------------------------------------------------------------

//这个方法用来判断是交给view的dispatch事件处理还是交给子view的dispatch处理

private boolean dispatchTransformedTouchEvent(MotionEvent ev, boolean cancel,

View child, int desiredPointerIdBits) {

将位置偏移到子view的相对位置,然后再派发事件

If(child==null){

return super.dispatchTouchEvent(ev);

}else{

return child.dispatchTouchEvent(ev);

}

}

View的dispatchTouchEvent方法

Public Boolean dispatchTouchEvent(MotionEvent ev){

//判断一下当前window是不是被遮挡

If(security){

If(onTouchListener!=null&&onTouchListner.onTouch(this,ev)){

return true;

}

//如果onTouchEvent返回true,view的dispatch方法也返回true;

If(onTouchEvent(ev){

return true;

}

}

return false;

}

View的touch事件:

Public Boolean onTouchEvent(MotionEvent ev){

//view基类处理了点击,长按和press等基本事件

}

Activity的dispatchTouchEvent事件:

public boolean dispatchTouchEvent(MotionEvent ev) {

if (ev.getAction() == MotionEvent.ACTION_DOWN) {

onUserInteraction();

}

if (getWindow().superDispatchTouchEvent(ev)) {

return true;

}

return onTouchEvent(ev);

}

Activity的onTouchEvent事件:

public boolean onTouchEvent(MotionEvent event) {

if (mWindow.shouldCloseOnTouch(this, event)) {

finish();

return true;

}

return false;

}

无任何拦截情况下的传递:

不做任何处理的情况下会尝试添加一次touchTarget,但没有添加成功,造成所有firstTouchTarget都为空,touchTarget也为空,直接走到firstTouchTarget==null的逻辑里。所以最后只有activity还相应up事件,其他view都不响应了。

ImageView的dispatch方法拦截后的传递:

ImageView的dispatch直接置成true,Relativelayout正常走进设置TouchTarget的代码,然后在最底下的代理while循环里,handle等于了true,递归下来所有父类的dispatchTouchEvent方法都返回true。

ImageView的touch事件拦截后的传递:

ImageView的onTouch只要是true,dispatchTouch肯定是true,父类正常走进设置TouchTarget,然后在最底下的while循环里,handle等于了true,递归下来所有父类的dispatchTouchEvent方法都返回true。

RelativeLayout的touch方法拦截后的传递:

第一次down到达Relativelayout,它需要找出子view中谁消耗了这个事件,如果子view都没有消耗,touchTarget和firstTouchTarget就都为空了。直接走到了firstTouchTarget==null的逻辑里了,即自己消耗事件。然后当接下来的事件传递过来后,就直接intercepted,然后走到firstTouchTarget为空的逻辑,不再往子view上传递了。

Relativelayout的intercept拦截事件后的传递

RelativeLayout的intercept方法拦截了,intercepted就为true,所以整个设置代理的过程就进不去了,直接走到了firstTouchTarget==null的逻辑,relativelayout本身自己处理。

这个情况和Relativelayout的dispatch方法直接返回true效果一样,只是少了onIntercept和onTouch的log而已。

这个情况下无论ImageView怎么写都不会有log出现。

所以总是所述:

dispatchTouchEvent是接受父类事件的第一个方法,本身有自己的控制在里面,如果重写这个方法的话,里面要加上对拦截和touch的方法的调用。

InterceptTouchEvent方法完全可以完成对touch事件的拦截,要不要交给子类去处理。一般情况下不需要对dispatch方法重写。

onTouchEvent方法就是具体的touch事件的处理,如果想继续往回传递,就返回false,如果自己消耗,就返回true。

时间: 2024-08-05 19:54:28

Touch事件的传递机制的相关文章

Android中Touch事件的传递机制

由于之前对于android的事件传递机制不了解,今天正好不忙,赶紧抽出时间来理一下这方面的知识,本文结合demo,对android的事件传递机制进行分析. 在事件传递过程中,离不开以下三个方法: 1.dispatchTouchEvent 分发touchEvent,返回值为true时表示TouchEvent被当前View处理,事件不会向下层传递(包括后续的onInterceptTouchEvent和onTouchEvent), dispatchTouchEvent会收到后续的ACTION_MOVE

android自定义控件系列教程-----touch事件的传递

前沿: 很久没有写过博客了,因为工作的原因很少有时间写东西了,最近想写一个UI系列的博客,因为我发现这一系列的都很少,而且没有那么系统,这里我想以我自己的观点来阐述一下如何自定义android 控件系列. 自定义控件阐述: 在我的理解里面自定义控件,需要了解到touch事件的传递.分发.拦截机制,Scroller类的运用,andorid 视图的理解,ViewGroup的熟悉,因为我们绝大多的控件都是继承自ViewGroup,还有就是要学会布局测量等. Touch事件的传递 首先我们要了解在and

[学习总结]4、Android的ViewGroup中事件的传递机制(一)

本文主要针对dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent三个方法,通过简单的例子来简单的介绍下. 根据字面意思的理解,dispatchTouchEvent分发触摸事件,onInterceptTouchEvent拦截触摸事件,onTouchEvent触摸事件.正如它们各自的字面意思,下面简单的列出各自的作用和用法. 1.dispatchTouchEvent作用:决定事件是否由onInterceptTouchEvent来拦截处理. 返回s

[学习总结]5、Android的ViewGroup中事件的传递机制(二)

下面是第一篇的连接 Android的ViewGroup中事件的传递机制(一) 关于onInterceptTouchEvent和onTouchEvent的详细解释. 1 public class MainActivity extends Activity { 2 Group1 group1; 3 Group2 group2; 4 MyTextView myTv; 5 6 /** Called when the activity is first created. */ 7 @Override 8

Android——View、ViewGroup事件(Touch事件)处理机制总结

Android中的事件 Touch事件,四种状态: ACTION_DOWN     -->   表示按下了屏幕,一个事件必然从ACTION_DOWN开始 ACTION_MOVE      -->   表示移动手势 ACTION_UP            -->  表示离开屏幕 ACTION_CANCEL  -->   表示取消手势,一般由程序产生,不会由用户产生 一个ACTION_DOWN, n个ACTION_MOVE,1个ACTION_UP,就构成了Android中众多的事件.

android touch事件的处理机制

一.在View里,有两个回调函数 (叶子view,不能添加控件的view,如:textview,imageview) public boolean dispatchTouchEvent(MotionEvent ev): public boolean onTouchEvent(MotionEvent ev); 二.在ViewGroup里,有三个回调函数 (layout,adapterview) public boolean dispatchTouchEvent(MotionEvent ev): p

Android初级教程:单击事件的传递机制初谈

以上仅是小试牛刀,后续有很多事件传递机制,继续探讨.

关于事件的传递机制。

每个ViewGroup都包含:onInterceptTouchEvent()和TouchEvent() 每个View包含:TouchEvent() 事件是从ViewGroup开始的之后经过传给ViewGroup或者View. 事件不可能一直往下传递,所以使用onInterceptTouchEvent()阻止事件像下面的控件传递. 使用TouchEvent() 阻止事件向上面的TouchEvent()传递.(使用返回值的方式true为已经被消耗,false为继续传递) 如:当返回值都为false的

Android Touch事件传递机制详解 上

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/37961997 最近总是遇到关于Android Touch事件的问题,如:滑动冲突的问题,以前也花时间学习过Android Touch事件的传递机制,可以每次用起来的时候总是忘记了,索性自己总结一下写篇文章避免以后忘记了,其实网上关于Touch事件的传递的文章真的很多,但是很少有系统性的,都是写了一个简单的demo运行了一下,对于我们了解Android Touch事件基本上没有任何帮助. 今