View的事件分发机制举例
- 为按钮设置onClick点击事件和onTouch触摸事件的执行顺序为:
1、onClick事件:
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "onClick execute");
}
});
2、onTouch事件:
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "onTouch execute, action " + event.getAction());
return false;
}
});
3、执行次序为:
onTouch是优先于onClick执行的,并且onTouch执行了两次,一次是按下ACTION_DOWN,一次是抬起ACTION_UP(你还可能会有多次移动ACTION_MOVE的执行,如果你手抖了一下)。因此事件传递的顺序是先经过onTouch,再传递到onClick。
4、onTouch方法是有返回值的,这里我们返回的是false,表示事件会继续传递;为true表示事件不继续传递了。(可以理解成事件被onTouch消费掉了)
- 只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法(该方法在View中)
dispatchTouchEvent源码为:
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
1、如果条件为真,则执行onTouch(this, event)方法,否则执行的是onTouchEvent(event);
3、三个条件依次是:注册监听 + 控件处于enabled状态 + onTouch方法的返回值(也就是如果这个onTouch回调函数的返回值为true,则执行onTouch而不会执行 onTouchEvent(event),否则执行的是onTouchEvent(event),这就是为什么刚刚说“被消耗掉”了的原因)
3、onClick方法在onTouchEvent(event)方法中,当按钮状态为MotionEvent.ACTION_UP(即点击)时,会执行performClick()方法里回调被点击控件的onClick方方法
- 就是touch事件的层级传递。
1、我们都知道如果给一个控件注册了touch事件,每次点击它的时候都会触发一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等事件。这里需要注意,如果你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action。
2、touch事件分发的机制总结为:
就拿按钮点击事件为例的touch事件分发的执行过程为:
①、当触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法
②、dispatchTouchEvent方法中首先会执行onTouch这个回调函数,但是执行onTouch这个回调函数有两个前提条件、第一个提前提条件是该控件注册了触摸监听,第二个条件是该控件是的状态是Enable的。
③、onTouch回调函数会有一个返回值,返回这如果为true的话就代表本次触摸事件被消耗掉了,执行接触;返回值为false的话会继续执行onTouchEvent方法。
④、onTouchEvent方法就是真正执行点击事件的地方,也就是我们重写的onClick方法。
⑤、onTouchEvent方法中能够捕获一次点击事件当中ACTION_DOWN、ACTION_ MOVE、ACTION_UP这三个中作,当触摸动作为ACTION_UP会调用onClick方法。
ViewGroup的事件分发机制
- ViewGroup的定义
Android中任何控件都是直接或者间接集成View的,ViewGroup也是一样,ViewGroup可以简单理解成一组View的集合,它里面既可以包含View,也可以包含ViewGroup,譬如说我们熟悉的LinearLayout、RelativeLayout布局就是ViewGroup的子类。 - ViewGroup的事件分发举例
1、MyLayout继承LinaerLayout + 两个Button + 设置监听
myLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "myLayout on touch");
return false;
}
});
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "You clicked button1");
}
});
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "You clicked button2");
}
});
2、分别点击的结果为:
即当点击按钮的时候,MyLayout注册的onTouch方法并不会执行,只有点击空白区域的时候才会执行该方法。
可以先理解成Button的onClick方法将事件消费掉了,因此事件不会再继续向下传递。
3、ViewGroup中有一个onInterceptTouchEvent方法
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
如果重写这个方法,返回true的话执行结果为:
3. ViewGroup事件分发的流程
1、Android中touch事件的传递,绝对是先传递到ViewGroup,再传递到View的
2、当你点击了某个控件,首先会去调用该控件所在ViewGroup的dispatchTouchEvent方法,然后在布局的dispatchTouchEvent方法中找到被点击的相应控件,再去调用该控件的dispatchTouchEvent方法。
3、其中会有一个onInterceptTouchEvent方法对事件传递进行拦截,如果返回值为true的话就表示事件不往子View中传递,如果为false的话就表示不对事件传递进行拦截,事件会往子View中传递
Android事件分发机制大总结
- Android中的控件都是直接或者间接继承View的,Viewgroup也是继承View的,ViewGroup中可以包含View,也可以包含ViewGroup,我们平时接触的譬如说LinearLayout啊、RelativeLayout就是ViewGroup的子类。
- Android的事件分发机制我有看过它的源码,总的来说就是Android中触摸事件的传递都是先传递到ViewGroup,再传递到View的。我就举Button点击这个例子来讲解一下Android中触摸事件分发的大致流程吧。
- 当点击Button的时候,会调用这个控件所在布局的dispatchTouchEvent(),然后在这个布局中dispatchTouchEvent()方法中找到被点击控件的dispatchTouchEvent()方法。
- 在调用被点击控件的dispatchTouchEvent()方法之前会有一次触摸事件的拦截判断,如果触摸事件被拦截了,就不会再去执行被点击控件的dispatchTouchEvent函数了,也就不会再执行onClick点击事件了。而是执行ViewGroup控件中的dispatchTouchEvent()的onTouch触摸事件然后返回。
- 如果触摸事件没被拦截的话又是怎么做呢,就会ViewGroup中dispatchTouchEvent()方法中被点击控件的dispatchTouchEvent()方法,就不会执行ViewGroup中的onTouch方法了。
- 以上只是阐述了touch事件在ViewGroup中和View中的事件分发过程,但是具体得在一个View中的touch事件分发机制又是怎么样的呢,我们继续往下看
- android里面当触摸到任何一个控件的时候就一定会调用这个控件的dispatchTouchEvent方法。dispatchTouchEvent方法中的源码首先会调用onTouch方法,不过这个方法要执行的话也需要有两个前提条件,一个是这个控件注册了触摸监听、第二个是这个控件的状态要是enabled的。
- 执行完onTouch方法之后,会有一个返回值,如果返回这为true的话代表这个点击事件不继续往下传递了,为false的话就表示点击事件继续往下传递,就会执行onTouchEvent方法,onClick方法就是在onTouchEvent中被调用的。
- 这样的话一个控件的触摸事件在ViewGroup以及View中的分发过程就完成了。