Android事件分发
一.view的事件分发
自定义一个button,分别实现的dispatchTouchEvent()和onTouchEvent()的监听,并且在activity实现button 的onTouch()的监听
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
/**
* Created by FWMS on 2017/6/5.
*/
public class MyButton extends android.support.v7.widget.AppCompatButton {
private String TAG=this.getClass().getName();
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action=event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN://按下
Log.e(TAG,"dispatchTouchEvent----ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE://
Log.e(TAG,"dispatchTouchEvent----ACTION_MOVE");
break;
case MotionEvent.ACTION_UP://
Log.e(TAG,"dispatchTouchEvent----ACTION_UP");
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action=event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN://按下
Log.e(TAG,"onTouchEvent----ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE://
Log.e(TAG,"onTouchEvent----ACTION_MOVE");
break;
case MotionEvent.ACTION_UP://
Log.e(TAG,"onTouchEvent----ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}
在activity的监听
findViewById(mBt).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onTouch ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onTouch ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "onTouch ACTION_UP");
break;
default:
break;
}
return false;
}
});
布局写好了,接下来让我们来看看这三个方法dispatchTouchEvent()、onTouchEvent()、onTouch()的执行步骤
当onTouch() return false的时候
执行顺序是dispatchTouchEvent()》onTouch()》onTouchEvent()
当onTouch() return true的时候
执行顺序是dispatchTouchEvent()》onTouch() 而onTouchEvent()不再执行 意味着onTouch()的时候已经将事件消费掉 不再由onTouchEvent()处理
最终得出结论:是执行顺序dispatchTouchEvent()》onTouch()》onTouchEvent() 但onTouchEvent() 不一定会执行
这还没有完 再添加一个OnClickListener事件
最后在ACTION_UP的时候回执行 如果onTouch()已经消费了该事件OnClickListener就不会执行
二.viewgroup事件分析
viewgroup比view多了拦截事件onInterceptTouchEvent()和requestDisallowInterceptTouchEvent()
同理来实现一个自定义linelayout
package com.example.fwms.eventouchdemo;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/**
* Created by FWMS on 2017/6/5.
*/
public class MyLinelayout extends LinearLayout {
private String TAG=this.getClass().getName();
public MyLinelayout(Context context) {
super(context);
}
public MyLinelayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyLinelayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action=event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN://按下
Log.e(TAG,"dispatchTouchEvent----ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE://
Log.e(TAG,"dispatchTouchEvent----ACTION_MOVE");
break;
case MotionEvent.ACTION_UP://
Log.e(TAG,"dispatchTouchEvent----ACTION_UP");
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action=event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN://按下
Log.e(TAG,"onTouchEvent----ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE://
Log.e(TAG,"onTouchEvent----ACTION_MOVE");
break;
case MotionEvent.ACTION_UP://
Log.e(TAG,"onTouchEvent----ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int action=event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN://按下
Log.e(TAG,"onInterceptTouchEvent----ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE://
Log.e(TAG,"onInterceptTouchEvent----ACTION_MOVE");
break;
case MotionEvent.ACTION_UP://
Log.e(TAG,"onInterceptTouchEvent----ACTION_UP");
break;
}
return super.onInterceptTouchEvent(event);
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Log.e(TAG,"requestDisallowInterceptTouchEvent");
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}
xml布局里面
<com.example.fwms.eventouchdemo.MyLinelayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.fwms.eventouchdemo.MyButton
android:id="@+id/mBt2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ViewGroub事件" />
com.example.fwms.eventouchdemo.MyLinelayout>
现在谁都不去消费事件,看看结果
MyLinelayout: dispatchTouchEvent》MyLinelayout: onInterceptTouchEvent》MyButton: dispatchTouchEvent》MyButton: onTouchEvent
最终发现viewgroup会将事件一个劲的传给子view 就像妈妈又好的东西吃,自己不舍得吃,就给了孩子,然后孩子也不要,为何viewgroup也不执行onTouchEvent?????有点不太合理,分着分着就凭空消失了
而点击外部就执行了onTouchEvent,可以这么理解touch事件被view消费了,子view要向下分发意味着这个touch事件被消费了才能下发,如何证明?
将onInterceptTouchEvent()返回TRUE 也就是说我不下发了,拦截掉,执行结果如下:
onInterceptTouchEvent()返回TRUE,就没有子view什么事了
最终得出结论:viewgroup会一直向子view传递事件,如果viewgroup拦截了该事件,子view就不会收到任何事件,如果viewgroup不拦截,而子view也消费了该事件,viewgroup就不会再收到。
三.事件冲突的解决
在开发中我们经常会遇到这么一个场景,viewgroup竖向滚动,子view横向滚动,这就容易发生了事件冲突,解决方法
1.viewgroup需要事件的时候onInterceptTouchEvent()返回TRUE 自己消费
2.子view不需要事件的时候requestDisallowInterceptTouchEvent(true) 请求viewgroup拦截事件,告诉viewgroup我不需要这个事件