dispathcTouchEvent() 返回值决定是否消耗事件 返回值由下面两个方法共同决定。 (这个方法通常不需要重写,只需要把下面两个方法处理正确,则会正确的分发)
onInterceptTouchEvent() 返回值决定是否拦截事件 ,有时不会调用。(所以内部拦截法要处理事件前需要写在dispathcTouchEvent方法中)
onTouchEvent();
public Boolean dispatchTouchEvent (MotionEvent ev){
boolean cosume=false;
if(onInterceptTouchEvent(ev)){
consume=onTouchEvent(ev);
}
else{
consume=child.dispatchTouchEvent(ev);
}
return consume;
}
不拦截: dispathchTouchEvent 向下传递
不消费:onTouchEvent 向上传递 类似于递归回调!(这点是很重要的 ,这种思想可以处理 最下级没有完成的事件,给父类容器一个机会继续处理)
Activity : 只有 dispathcTouchEvent ,和onTouchEvnet方法
ViewGroup : 三个方法都存在
view : 没有onInterceptTouchEvent 方法(因为直接拦截了), 返回值默认为true 消耗事件。
一, 从头到尾都无拦截无消耗:
则dispathchTouchEvent返回为false ,说明消息发送失败. 假如DOWN事件被传递后,无拦截,无消耗,则后续的MOVE,和UP事件不会在传递了!
二.默认被view拦截了,并且消耗掉事件了。 则后面的点击后续事件,都会来找这个View(因为dispathcTouchEvent 上面的返回值都是true)
三. 特殊情况
1:被拦截了,并且消耗了事件后,又被前面的给拦截了, 那么跟这个最初拦截的view 就基本没什么关系了,只传递了 CANCEL一个事件给这个view。
2:一开始就被拦截并且也消费了,则跟后面的view 一毛钱关系都没有了。
特别注意 :
如果DOWN事件被消费,后续的MOVE和UP也归这个view. 通过阅读源码,可以知道,是因为firstTouchTage这个标记被更改为true 导致 后续事件将不会调用onInterceptTouch方法询问是否拦截了!
如果DOWN事件不消费,后续的MOVE 和up事件会递归调用父容器的TouchEvent方法
如果出了DOWN以外的事件不消费,那么不会调用父容器的TouchEvent方法,并且听说事件会失效,并交给Activty处理。
onTouchListner 优先级最高
onTouchEvent 第二
onClicListener 第三
如果返回的true 表示消费后后面的方法就不会调用了!
1.通常情况下一个事件序列只能被一个View拦截并消耗。(即down,move,up都交给一个view处理)
2.一旦View开始处理事件那么整个事件序列都交给它处理,onIntercept不会再次调用,因为不再需要确认是否拦截了也合乎情理。
3.ViewGroup的拦截与ACTION_DOWN这个方法和FLAG_DisALLOW标记有关。(根据这点可以用内部拦截法处理滑动冲突)内部拦截法就是回路拦截
处理事件后如果不消耗,ACTION_DOWN事件那么后面的事件不会再交给当前view而会交给父容器处理,而非ACTION_DOWN事件则不会调用父容器,会传给Activity处理。
最后外部拦截法处理冲突的方式:
外部拦截法就是 InterceptTouchEvent()方法获取到事件后 判断是不是要拦下 ,如果不需要这个事件就不拦 返回false 给下面处理。如果需要就返回true
但是特别需要注意的有以下两点:
1.ACTION_DOWN 这个事件一定不能拦截 ,因为 如果拦下之后,后续的事件都会归当前这个view 处理!
2.ACTION_UP这个事件也没有必要拦 ,返回false 就可以了, 拦也没有什么意义。
代码如下:(核心思想就是针对MOVE事件进行判断和拦截)
public boolean onInterceptTouchEvent(MotionEvent ev) {
Boolean intercept=false;
//获取坐标点:
int x= (int) ev.getX();
int y= (int) ev.getY();
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
intercept=false;
break;
case MotionEvent.ACTION_MOVE:
int deletx=x-mx;
int delety=y-my;
if(Math.abs(deletx)>Math.abs(delety))
{
intercept=true;
Log.d("拦截了","111");
}
else {
intercept=false;
Log.d("没拦截","222");
}
break;
case MotionEvent.ACTION_UP:
intercept=false;
break;
default:
break;
}
//这里尤其重要,解决了拦截MOVE事件却没有拦截DOWN事件没有坐标的问题
lastx=x;
lasty=y;
mx=x;
my=y;
return intercept;
}
}
上次滑动点坐标lx,ly; !!!这个很重要!!
lx,ly坐标重置 这次重置是为了下一次MOVE事件时提供初始值。 !!!这个很重要!!
特别注意这段代码的一些细节,例如坐标需要重置!
滑动也是view事件的责任:
第二部分是view事件处理:
主要是view滑动(7种):
通过ontouchListener()
1获取偏移()
2将偏移量放进位置方法中改变位置。
附练习代码
https://github.com/cuizehui/myDemo