ViewGroup事件的传递和消耗
ViewGroup事件的消耗和传递主要由下面三个方法实现
dispatchTouchEvent(MotionEvent ev)
用于事件的分发,Android
中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true
表示不继续分发,事件没有被消费。返回false
则继续往下分发,如果是ViewGroup
则分发给子View。
onInterceptTouchEvent()
是ViewGroup
中才有的方法,View
中没有,它的作用是负责事件的拦截,返回true
的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent
进行处理。返回false
则不拦截,继续往下传。这是ViewGroup
特有的方法,因为ViewGroup
中可能还有子View
,而在Android
中View
是不能再包含子View
的。
onTouchEvent(MotionEvent event)
用于事件的处理,返回true
表示消费当前事件,返回false
则不处理,交给子控件继续分发。
事件传递分析
事件分发

其中红色为ViewGroupA
,绿色为ViewGroupB
,蓝色为MyView
。
public class ViewGroupA extends RelativeLayout {
public ViewGroupA(Context context) {
super(context);
}
public ViewGroupA(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupA(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(getClass().getSimpleName(),"dispatchTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(getClass().getSimpleName(),"dispatchTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(getClass().getSimpleName(),"dispatchTouchEvent:ACTION_UP");
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_UP");
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(getClass().getSimpleName(),"onTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(getClass().getSimpleName(),"onTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(getClass().getSimpleName(),"onTouchEvent:ACTION_UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
1. 全部super父类的方法
打印日志:
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN
D/ViewGroupB: onTouchEvent:ACTION_DOWN
D/ViewGroupA: onTouchEvent:ACTION_DOWN
D/MainActivity: onTouchEvent:ACTION_DOWN
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/MainActivity: onTouchEvent:ACTION_UP
可以发现事件传递的方向是由外向内,如果都不消耗此事件,最后MainActivity会消耗掉。
2. MyView消耗掉事件
将MyView添加一个属性android:clickable="true"
----------------ACTION_DOWN-------------------
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN
----------------ACTION_MOVE-------------------
D/MainActivity: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: onInterceptTouchEvent:ACTION_MOVE
D/ViewGroupB: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupB: onInterceptTouchEvent:ACTION_MOVE
D/MyView: dispatchTouchEvent:ACTION_MOVE
D/MyView: onTouchEvent:ACTION_MOVE
----------------ACTION_UP-------------------
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: onInterceptTouchEvent:ACTION_UP
D/ViewGroupB: dispatchTouchEvent:ACTION_UP
D/ViewGroupB: onInterceptTouchEvent:ACTION_UP
D/MyView: dispatchTouchEvent:ACTION_UP
D/MyView: onTouchEvent:ACTION_UP
3. ViewGroupB拦截MOVE和UP事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_DOWN");
return false;
case MotionEvent.ACTION_MOVE:
Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_MOVE");
return true;
case MotionEvent.ACTION_UP:
Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_UP");
return true;
default:
break;
}
return false;
}
打印日志
----------Action_Down----------
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN
----------Action_Move----------
D/MainActivity: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: onInterceptTouchEvent:ACTION_MOVE
D/ViewGroupB: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupB: onInterceptTouchEvent:ACTION_MOVE
----------Action_Up----------
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: onInterceptTouchEvent:ACTION_UP
D/ViewGroupB: dispatchTouchEvent:ACTION_UP
D/ViewGroupB: onTouchEvent:ACTION_UP
D/MainActivity: onTouchEvent:ACTION_UP
可以看到Action_Move和Action_Up只传递到ViewGroupB。
4. 在MyView中使用getParent().requestDisallowInterceptTouchEvent(true)
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
Log.d(getClass().getSimpleName(), "onTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(getClass().getSimpleName(), "onTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(getClass().getSimpleName(), "onTouchEvent:ACTION_UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
打印日志
----------Action_Down----------
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN
----------Action_Move----------
D/MainActivity: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupB: dispatchTouchEvent:ACTION_MOVE
D/MyView: dispatchTouchEvent:ACTION_MOVE
D/MyView: onTouchEvent:ACTION_MOVE
----------Action_Up----------
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: dispatchTouchEvent:ACTION_UP
D/ViewGroupB: dispatchTouchEvent:ACTION_UP
D/MyView: dispatchTouchEvent:ACTION_UP
D/MyView: onTouchEvent:ACTION_UP
可以发现MOVE和UP事件又可以传递到MyView中了。
网友评论