ViewGroup onInterceptTouchEvent and OnTouchEvent

ViewGroup 继承View,实现了View各个方法,同时ViewGroup中包含了不同的View,事件消息在ViewGroup中的传递就比较重要了,理解了事件的传递,才能够写出符合需求的自定义的ViewGroup。

首先分析一下onInterceptTouchEvent函数,此函数是ViewGroup独有的拦截函数,顾名思义,是拦截用户触发的事件,来决定此事件是否要传递给子View。原理比较简单,但是传递流程稍许复杂。

先看一段官方的文档:

· You will receive the down event here.
· The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal.
· For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
· If you return true from here, you will not receive any following events: the target view will receive the same event but with the action ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.

看着头昏脑涨,在来一段中文的翻译:
由于onInterceptTouchEvent()的机制比较复杂,上面的说明写的也比较复杂,总结一下,基本的规则是:
1. down事件首先会传递到onInterceptTouchEvent()方法
2. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。
3. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。
4. 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。
5. 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

这里重要一点是对down事件的处理,这里是决定消息是分发给子View还是自己处理的关键点。


demo1: layout以及子View onTouchEvent 返回true

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
// break;
return true;
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
break;
// return true;
case MotionEvent.ACTION_UP:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");
break;
// return true;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
break;

}
return false;
}

在layout中拦截ACTION_DOWN,子类view不会收到任何消息,而是直接把消息分发给layout的OnToucheEvent处理

D/LayoutView2(15426): onInterceptTouchEvent action:ACTION_DOWN
D/LayoutView2(15426): onTouchEvent action:ACTION_DOWN
D/LayoutView2(15426): onTouchEvent action:ACTION_MOVE
D/LayoutView2(15426): onTouchEvent action:ACTION_MOVE
D/LayoutView2(15426): onTouchEvent action:ACTION_MOVE
D/LayoutView2(15426): onTouchEvent action:ACTION_MOVE
D/LayoutView2(15426): onTouchEvent action:ACTION_MOVE
D/LayoutView2(15426): onTouchEvent action:ACTION_MOVE
D/LayoutView2(15426): onTouchEvent action:ACTION_UP


Demo2:layout 拦截ACTION_MOVE layout以及子View onTouchEvent 返回true
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
break;
// return true;
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
// break;
return true;
case MotionEvent.ACTION_UP:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");
break;
// return true;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
break;

}
return false;
}
layout的消息传递:
D/LayoutView2(15765): onInterceptTouchEvent action:ACTION_DOWN
D/LayoutView2(15765): onInterceptTouchEvent action:ACTION_MOVE
D/LayoutView2(15765): onTouchEvent action:ACTION_MOVE
D/LayoutView2(15765): onTouchEvent action:ACTION_UP

也就是当 action:ACTION_MOVE被拦截时,action:ACTION_MOVE后续的消息直接传递给onTouchEvent

子View的消息传递为:
D/MyTextView(15765): onTouchEvent action:ACTION_DOWN
D/MyTextView(15765): onTouchEvent action:ACTION_CANCEL (这个消息一直没有弄明白)


Demo3:layout 拦截ACTION_MOVE layout onTouchEvent 返回true 子View的onTouchEvent返回false

public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
break;
// return true;
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
break;
// return true;
case MotionEvent.ACTION_UP:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");
break;
// return true;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
break;

}
return false;
}


layout的消息传递:

D/LayoutView2(16536): onInterceptTouchEvent action:ACTION_DOWN
D/LayoutView2(16536): onTouchEvent action:ACTION_DOWN
D/LayoutView2(16536): onTouchEvent action:ACTION_MOVE
D/LayoutView2(16536): onTouchEvent action:ACTION_UP

子View消息传递:
D/MyTextView(16536): onTouchEvent action:ACTION_DOWN


这里消息向下拦截的逻辑,当onInterceptTouchEvent拦截了ACTION_MOVE后,ACTION_MOVE后的消息就不在分发给子View,而是分发给layout的OnTouchEvent。

如果Layout的onInterceptTouchEvent对ACTION_DOWN消息没有拦截,但是子View的OntouchEvent不处理这些消息,仍会返回Layout的OnTouchEvent,如果Layout的OnTouchEvent对ACTION_DOWN消息进行了处理,后续的消息就会直接发送到Layout的OnTouchEvent。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值