Android事件传递机制

实验环境

OS X 10.9
Eclipse(ADT)
Android源码版本:API Level 19(Android 4.4)

Android事件构成

在Android中,事件主要包括点按、长按、拖拽、滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作。所有这些都构成了Android中的事件响应。总的来说,所有的事件都由如下三个部分作为基础:

按下(ACTION_DOWN)
移动(ACTION_MOVE)
抬起(ACTION_UP)

所有的操作事件首先必须执行的是按下操作(ACTIONDOWN),之后所有的操作都是以按下操作作为前提,当按下操作完成后,接下来可能是一段移动(ACTIONMOVE)然后抬起(ACTION_UP),或者是按下操作执行完成后没有移动就直接抬起。这一系列的动作在Android中都可以进行控制。

我们知道,所有的事件操作都发生在触摸屏上,而在屏幕上与我们交互的就是各种各样的视图组件(View),在Android中,所有的视图都继承于View,另外通过各种布局组件(ViewGroup)来对View进行布局,ViewGroup也继承于View。所有的UI控件例如Button、TextView都是继承于View,而所有的布局控件例如RelativeLayout、容器控件例如ListView都是继承于ViewGroup。所以,我们的事件操作主要就是发生在View和ViewGroup之间,那么View和ViewGroup中主要有哪些方法来对这些事件进行响应呢?记住如下3个方法,我们通过查看View和ViewGroup的源码可以看到:

View.java

public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event) 

ViewGroup.java

public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)

在View和ViewGroup中都存在dispatchTouchEvent和onTouchEvent方法,但是在ViewGroup中还有一个onInterceptTouchEvent方法,那这些方法都是干嘛的呢?别急,我们先看看他们的返回值。这些方法的返回值全部都是boolean型,为什么是boolean型呢,看看本文的标题,“事件传递”,传递的过程就是一个接一个,那到了某一个点后是否要继续往下传递呢?你发现了吗,“是否”二字就决定了这些方法应该用boolean来作为返回值。没错,这些方法都返回true或者是false。在Android中,所有的事件都是从开始经过传递到完成事件的消费,这些方法的返回值就决定了某一事件是否是继续往下传,还是被拦截了,或是被消费了。

接下来就是这些方法的参数,都接受了一个MotionEvent类型的参数,MotionEvent继承于InputEvent,用于标记各种动作事件。之前提到的ACTIONDOWN、ACTIONMOVE、ACTION_UP都是MotinEvent中定义的常量。我们通过MotionEvent传进来的事件类型来判断接收的是哪一种类型的事件。到现在,这三个方法的返回值和参数你应该都明白了,接下来就解释一下这三个方法分别在什么时候处理事件。

dispatchTouchEvent方法用于事件的分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件。

onTouchEvent方法用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。
onInterceptTouchEvent是ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的(iOS可以)。
到目前为止,Android中事件的构成以及事件处理方法的作用你应该比较清楚了,接下来我们就通过一个Demo来实际体验实验一下。

Android事件处理

首先在Eclipse新建一个工程,并新建一个类RTButton继承Button,用来实现我们对按钮事件的跟踪。

RTButton.java

public class RTButton extends Button {
public RTButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTButton---dispatchTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTButton---dispatchTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTButton---dispatchTouchEvent---UP");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTButton---onTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTButton---onTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTButton---onTouchEvent---UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}

在RTButton中我重写了dispatchTouchEvent和onTouchEvent方法,并获取了MotionEvent各个事件状态,打印输出了每一个状态下的信息。然后在activity_main.xml中直接在根布局下放入自定义的按钮RTButton。

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/myLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.ryantang.eventdispatchdemo.RTButton
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"/>
</LinearLayout>

接下来在Activity中为RTButton设置onTouch和onClick的监听器来跟踪事件传递的过程,另外,Activity中也有一个dispatchTouchEvent方法和一个onTouchEvent方法,我们也重写他们并输出打印信息。

MainActivity.java

public class MainActivity extends Activity {
private RTButton button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (RTButton)this.findViewById(R.id.btn);
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTButton---onTouch---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTButton---onTouch---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTButton---onTouch---UP");
break;
default:
break;
}
return false;
}
});
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("RTButton clicked!");
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("Activity---dispatchTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("Activity---dispatchTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("Activity---dispatchTouchEvent---UP");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("Activity---onTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("Activity---onTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("Activity---onTouchEvent---UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}

代码部分已经完成了,接下来运行工程,并点击按钮,查看日志输出信息,我们可以看到如下结果:

通过日志输出可以看到,首先执行了Activity的dispatchTouchEvent方法进行事件分发,在MainActivity.java代码第55行,dispatchTouchEvent方法的返回值是super.dispatchTouchEvent(event),因此调用了父类方法,我们进入Activity.java的源码中看看具体实现。

Activity.java

/**
* Called to process touch screen events. You can override this to
* intercept all touch screen events before they are dispatched to the
* window. Be sure to call this implementation for touch screen events
* that should be handled normally.
*
* @param ev The touch screen event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}

从源码中可以看到,dispatchTouchEvent方法只处理了ACTIONDOWN事件,前面提到过,所有的事件都是以按下为起点的,所以,Android认为当ACTIONDOWN事件没有执行时,后面的事件都是没有意义的,所以这里首先判断ACTION_DOWN事件。如果事件成立,则调用了onUserInteraction方法,该方法可以在Activity中被重写,在事件被分发前会调用该方法。该方法的返回值是void型,不会对事件传递结果造成影响,接着会判断getWindow().superDispatchTouchEvent(ev)的执行结果,看看它的源码:

Activity.java

/**
* Used by custom windows, such as Dialog, to pass the touch screen event
* further down the view hierarchy. Application developers should
* not need to implement or call this.
*
*/
public abstract boolean superDispatchTouchEvent(MotionEvent event);

通过源码注释我们可以了解到这是个抽象方法,用于自定义的Window,例如自定义Dialog传递触屏事件,并且提到开发者不需要去实现或调用该方法,系统会完成,如果我们在MainActivity中将dispatchTouchEvent方法的返回值设为true,那么这里的执行结果就为true,从而不会返回执行onTouchEvent(ev),如果这里返回false,那么最终会返回执行onTouchEvent方法,由此可知,接下来要调用的就是onTouchEvent方法了。别急,通过日志输出信息可以看到,ACTION_DOWN事件从Activity被分发到了RTButton,接着执行了onTouch和onTouchEvent方法,为什么先执行onTouch方法呢?我们到RTButton中的dispatchTouchEvent看看View中的源码是如何处理的。

View.java

/**
* Pass the touch screen motion event down to the target view, or this
* view if it is the target.
*
* @param event The motion event to be dispatched.
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchTouchEvent(MotionEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null && (mViewFlags &
ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {
return true;
}
if (onTouchEvent(event)) {
return true;
}
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}

挑选关键代码进行分析,可以看代码第16行,这里有几个条件,当几个条件都满足时该方法就返回true,当条件li.mOnTouchListener不为空时,通过在源码中查找,发现mOnTouchListener是在以下方法中进行设置的。

View.java

/**
* Register a callback to be invoked when a touch event is sent to this view.
* @param l the touch listener to attach to this view
*/
public void setOnTouchListener(OnTouchListener l) {
getListenerInfo().mOnTouchListener = l;
}

这个方法就已经很熟悉了,就是我们在MainActivity.java中为RTButton设置的onTouchListener,条件(mViewFlags & ENABLED_MASK) == ENABLED判断的是当前View是否是ENABLE的,默认都是ENABLE状态的。接着就是li.mOnTouchListener.onTouch(this, event)条件,这里调用了onTouch方法,该方法的调用就是我们在MainActivity.java中为RTButton设置的监听回调,如果该方法返回true,则整个条件都满足,dispatchTouchEvent就返回true,表示该事件就不继续向下分发了,因为已经被onTouch消费了。

如果onTouch返回的是false,则这个判断条件不成立,接着执行onTouchEvent(event)方法进行判断,如果该方法返回true,表示事件被onTouchEvent处理了,则整个dispatchTouchEvent就返回true。到这里,我们就可以回答之前提出的“为什么先执行onTouch方法”的问题了。到目前为止,ACTIONDOWN的事件经过了从Activity到RTButton的分发,然后经过onTouch和onTouchEvent的处理,最终,ACTIONDOWN事件交给了RTButton得onTouchEvent进行处理。

当我们的手(我这里用的Genymotion然后用鼠标进行的操作,用手的话可能会执行一些ACTIONMOVE操作)从屏幕抬起时,会发生ACTIONUP事件。从之前输出的日志信心中可以看到,ACTIONUP事件同样从Activity开始到RTButton进行分发和处理,最后,由于我们注册了onClick事件,当onTouchEvent执行完毕后,就调用了onClick事件,那么onClick是在哪里被调用的呢?继续回到View.java的源代码中寻找。由于onTouchEvent在View.java中的源码比较长,这里就不贴出来了,感兴趣的可以自己去研究一下,通过源码阅读,我们在ACTIONUP的处理分支中可以看到一个performClick()方法,从这个方法的源码中可以看到执行了哪些操作。

View.java

/**
* Call this view's OnClickListener, if it is defined. Performs all normal
* actions associated with clicking: reporting accessibility event, playing
* a sound, etc.
*
* @return True there was an assigned OnClickListener that was called, false
* otherwise is returned.
*/
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
return true;
}
return false;
}

在if分支里可以看到执行了li.mOnClickListener.onClick(this);这句代码,这里就执行了我们为RTButton实现的onClick方法,所以,到目前为止,可以回答前一个“onClick是在哪里被调用的呢?”的问题了,onClick是在onTouchEvent中被执行的,并且,onClick要后于onTouch的执行。

到此,点击按钮的事件传递就结束了,我们结合源代码窥探了其中的执行细节,如果我们修改各个事件控制方法的返回值又会发生什么情况呢,带着这个问题,进入下一节的讨论。

Android事件拦截

从上一节分析中,我们知道了在Android中存在哪些事件类型,事件的传递过程以及在源码中对应哪些处理方法。我们可以知道在Android中,事件是通过层级传递的,一次事件传递对应一个完整的层级关系,例如上节中分析的ACTIONDOWN事件从Activity传递到RTButton,ACTIONUP事件也同样。结合源码分析各个事件处理的方法,也可以明确看到事件的处理流程。

之前提过,所有事件处理方法的返回值都是boolean类型的,现在我们来修改这个返回值,首先从Activity开始,根据之前的日志输出结果,首先执行的是Activity的dispatchTouchEvent方法,现在将之前的返回值super.dispatchTouchEvent(event)修改为true,然后重新编译运行并点击按钮,看到如下的日志输出结果。

可以看到,事件执行到dispatchTouchEvent方法就没有再继续往下分发了,这也验证了之前的说法,返回true时,不再继续往下分发,从之前分析过的Activity的dispatchTouchEvent源码中也可知,当返回true时,就没有去执行onTouchEvent方法了。

接着,将上述修改还原,让事件在Activity这继续往下分发,接着就分发到了RTButton,将RTButton的dispatchTouchEvent方法的返回值修改为true,重新编译运行并查看输出日志结果。

从结果可以看到,事件在RTButton的dispatchTouchEvent方法中就没有再继续往下分发了。接着将上述修改还原,将RTButton的onTouchEvent方法返回值修改为true,让其消费事件,根据之前的分析,onClick方法是在onTouchEvent方法中被调用的,事件在这被消费后将不会调用onClick方法了,编译运行,得到如下日志输出结果。

跟分析结果一样,onClick方法并没有被执行,因为事件在RTButton的onTouchEvent方法中被消费了。下图是整个事件传递的流程图。

到目前为止,Android中的事件拦截机制就分析完了。但这里我们只讨论了单布局结构下单控件的情况,如果是嵌套布局,那情况又是怎样的呢?接下来我们就在嵌套布局的情况下对Android的事件传递机制进行进一步的探究和分析。

Android嵌套布局事件传递

首先,新建一个类RTLayout继承于LinearLayout,同样重写dispatchTouchEvent和onTouchEvent方法,另外,还需要重写onInterceptTouchEvent方法,在文章开头介绍过,这个方法只有在ViewGroup和其子类中才存在,作用是控制是否需要拦截事件。这里不要和dispatchTouchEvent弄混淆了,后者是控制对事件的分发,并且后者要先执行。

那么,事件是先传递到View呢,还是先传递到ViewGroup的?通过下面的分析我们可以得出结论。首先,我们需要对工程代码进行一些修改。

RTLayout.java

public class RTLayout extends LinearLayout {
public RTLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTLayout---dispatchTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTLayout---dispatchTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTLayout---dispatchTouchEvent---UP");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTLayout---onInterceptTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTLayout---onInterceptTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTLayout---onInterceptTouchEvent---UP");
break;
default:
break;
}
return super.onInterceptTouchEvent(event);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTLayout---onTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTLayout---onTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTLayout---onTouchEvent---UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}

同时,在布局文件中为RTButton添加一个父布局,指明为自定义的RTLayout,修改后的布局文件如下。

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" >
<com.ryantang.eventdispatchdemo.RTLayout
android:id="@+id/myLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.ryantang.eventdispatchdemo.RTButton
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
</com.ryantang.eventdispatchdemo.RTLayout>
</LinearLayout>

最后,我们在Activity中也为RTLayout设置onTouch和onClick事件,在MainActivity中添加如下代码。

MainActivity.java

rtLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTLayout---onTouch---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTLayout---onTouch---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTLayout---onTouch---UP");
break;
default:
break;
}
return false;
}
});
rtLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("RTLayout clicked!");
}
});

代码修改完毕后,编译运行工程,同样,点击按钮,查看日志输出结果如下:

从日志输出结果我们可以看到,嵌套了RTLayout以后,事件传递的顺序变成了Activity->RTLayout->RTButton,这也就回答了前面提出的问题,Android中事件传递是从ViewGroup传递到View的,而不是反过来传递的。

从输出结果第三行可以看到,执行了RTLayout的onInterceptTouchEvent方法,该方法的作用就是判断是否需要拦截事件,我们到ViewGroup的源码中看看该方法的实现。

ViewGroup.java

public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}

该方法的实现很简单,只返回了一个false。那么这个方法是在哪被调用的呢,通过日志输出分析可知它是在RTLayout的dispatchTouchEvent执行后执行的,那我们就进到dispatchTouchEvent源码里面去看看。由于源码比较长,我将其中的关键部分截取出来做解释说明。

ViewGroup.java

// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}

从这部分代码中可以看到onInterceptTouchEvent调用后返回值被赋值给intercepted,该变量控制了事件是否要向其子控件分发,所以它起到拦截的作用,如果onInterceptTouchEvent返回false则不拦截,如果返回true则拦截当前事件。我们现在将RTLayout中的该方法返回值修改为true,并重新编译运行,然后点击按钮,查看输出结果如下。

可以看到,我们明明点击的按钮,但输出结果显示RTLayout点击事件被执行了,再通过输出结果分析,对比上次的输出结果,发现本次的输出结果完全没有RTButton的信息,没错,由于onInterceptTouchEvent方法我们返回了true,在这里就将事件拦截了,所以他不会继续分发给RTButton了,反而交给自身的onTouchEvent方法执行了,理所当然,最后执行的就是RTLayout的点击事件了。

总结

以上我们对Android事件传递机制进行了分析,期间结合系统源码对事件传递过程中的处理情况进行了探究。通过单布局情况和嵌套布局情况下的事件传递和处理进行了分析,现总结如下:

Android中事件传递按照从上到下进行层级传递,事件处理从Activity开始到ViewGroup再到View。
事件传递方法包括dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent,其中前两个是View和ViewGroup都有的,最后一个是只有ViewGroup才有的方法。这三个方法的作用分别是负责事件分发、事件处理、事件拦截。
onTouch事件要先于onClick事件执行,onTouch在事件分发方法dispatchTouchEvent中调用,而onClick在事件处理方法onTouchEvent中被调用,onTouchEvent要后于dispatchTouchEvent方法的调用。

(0)

相关推荐

  • 详细分析Android中onTouch事件传递机制

    onTach介绍 ontach是Android系统中整个事件机制的基础.Android中的其他事件,如onClick.onLongClick等都是以onTach为基础的. onTach包括从手指按下到离开手机屏幕的整个过程,在微观形式上,具体表现为action_down.action_move和action_up等过程. onTach两种主要定义形式如下: 1.在自定义控件中,常见的有重写onTouchEvent(MotionEvent ev)方法.如在开发中经常可以看到重写的onTouchEv

  • 深入解析Android中的事件传递

    前言 前段时间工作中遇到了一个问题,即在软键盘弹出后想监听back事件,但是在Activity中重写了对应的onKeyDown函数却怎么也监听不到,经过一阵Google之后才发现需要重写View的dispatchKeyEventPreIme函数才行.当时就觉得这个函数名字很熟悉,仔细思索一番以后才恍然大悟,当初看WMS源码的时候有过这方面的了解,现在却把它忘到了九霄云外,于是决定写这篇文章,权当记录. InputManagerService 首先我们知道,不论是"键盘事件"还是&quo

  • Android触摸事件传递图解

    本博文讲解流程 TouchEvent相关事件简介 流程图分解讲解 总结与归纳 一.TouchEvent相关事件简介 android TouchEvent相关事件有  1 dispatchTouchEvent 这个方法用来分发TouchEvent  2 onInterceptTouchEvent 这个方法用来拦截TouchEvent  3 onTouchEvent 方法用来处理TouchEvent 比较特殊一点的是onInterceptTouchEvent 事件,在activity中和view中是

  • Android Drawerlayout侧拉栏事件传递问题的解决方法

    先来看看错误分析: "在侧拉栏打开的时候出现了点击之后侧拉栏下面的页面也接收到了点击事件." 解决方案: rootDrawerlayout.setDrawerListener(new DrawerLayout.DrawerListener() { //当侧拉栏滑动的时候调用此方法 @Override public void onDrawerSlide(View drawerView, float slideOffset) { }//当侧拉栏打开的时候调用此方法 @Override pu

  • Android事件传递机制

    实验环境 OS X 10.9 Eclipse(ADT) Android源码版本:API Level 19(Android 4.4) Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作.所有这些都构成了Android中的事件响应.总的来说,所有的事件都由如下三个部分作为基础: 按下(ACTION_DOWN) 移动(ACTION_MOVE) 抬起(ACTION_UP) 所有的操作事件首先必须执行的是按下操作(ACTIO

  • Android触摸事件传递机制初识

    前言 今天总结的一个知识点是Andorid中View事件传递机制,也是核心知识点,相信很多开发者在面对这个问题时候会觉得困惑,另外,View的另外一个难题滑动冲突,比如在ScrollView中嵌套ListView,都是上下滑动,这该如何解决呢,它解决的依据就是View事件的传递机制,所以开发者需要对View的事件传递机制有较深入的理解. 目录 Activity.View.ViewGroup三者关系 触摸事件类型 事件传递三个阶段 View事件传递机制 ViewGroup事件传递机制 小结 Act

  • Android触摸事件传递机制

    前言:在Android开发中,经常会遇到触摸事件冲突,比如ViewPager的轮播图跟Fragment的划动事件冲突,或者轮播图跟下拉事件冲突,自定义view的事件处理等,本文章将会详细介绍Activity.View.ViewGroup三者的触摸事件传递机制,传递包括三个阶段:分发.拦截.消费. 本文章将会详细介绍Activity.View.ViewGroup三者的触摸事件传递机制,传递包括三个阶段:分发.拦截.消费. 一.触摸事件的类型 触摸事件对应的是 MotionEvent 类,事件类型主

  • Android事件分发机制的详解

    Android事件分发机制 我们只考虑最重要的四个触摸事件,即:DOWN,MOVE,UP和CANCEL.一个手势(gesture)是一个事件列,以一个DOWN事件开始(当用户触摸屏幕时产生),后跟0个或多个MOVE事件(当用户四处移动手指时产生),最后跟一个单独的UP或CANCEL事件(当用户手指离开屏幕或者系统告诉你手势(gesture)由于其他原因结束时产生).当我们说到"手势剩余部分"时指的是手势后续的MOVE事件和最后的UP或CANCEL事件. 在这里我也不考虑多点触摸手势(我

  • Android事件分发机制全面解析

    事件分发机制 事件分发机制的两个阶段: 分发:事件从父视图往子视图分发,被拦截后不再传递,进入回溯阶段 回溯:事件从子视图往父视图回溯,被消费后不再回溯 关键方法: ViewGroup.dispatchTouchEvent 往子视图分发事件 ViewGroup.onInterceptTouchEvent 返回 true 表示拦截分发事件,不再传递,进入当前视图 onTouchEvent View.dispatchTouchEvent 默认事件分发,调用 onTouchEvent View.onT

  • Android事件分发机制示例分析

    Android事件类型 public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_CANCEL: break; } return tru

  • Android 事件触发机制的深入学习

     Android 事件触发机制的深入学习 最近在研究android的事件触发和传播机制,说来很惭愧,web下的事件太熟悉不过了,可在android中却很郁闷,常用的触摸事件都糊里糊涂的,在网上看了半天,也整理一份,供大家参考: public class CustomDefaultActivity implements OnTouchListener { private GestureDetector gd1; private TableLayout tableLayout; @Override

  • Android事件分发机制 ViewGroup分析

    目录 整体流程 源码分析 前言: 事件分发从手指触摸屏幕开始,即产生了触摸信息,被底层系统捕获后会传递给Android的输入系统服务IMS,通过Binder把消息发送到activity,activity会通过phoneWindow.DecorView最终发送给ViewGroup.这里就直接分析ViewGroup的事件分发 整体流程 配合图在看一段伪代码: public boolean dispatchTouchEvent(MotionEvent ev) :Boolean{ val result

  • Android事件分发机制(上) ViewGroup的事件分发

    综述 Android中的事件分发机制也就是View与ViewGroup的对事件的分发与处理.在ViewGroup的内部包含了许多View,而ViewGroup继承自View,所以ViewGroup本身也是一个View.对于事件可以通过ViewGroup下发到它的子View并交由子View进行处理,而ViewGroup本身也能够对事件做出处理.下面就来详细分析一下ViewGroup对时间的分发处理. MotionEvent 当手指接触到屏幕以后,所产生的一系列的事件中,都是由以下三种事件类型组成.

随机推荐