阅读本篇文章之前,建议先阅读Android 事件分发机制(1)-源码分析_z936689039的博客-CSDN博客
1.案例1
这块得采用ViewGroup中发现ps小总结咯:
1.当ACTION_MOVE和ACTION_UP事件到来时,如果没有子元素处理事件(mFirstTouchTarget==null),则ViewGroup的onInterceptTouchEvent不会再被调用,而且同一序列中的其它事件都会默认交给它处理( intercepted=true),都由 ViewGroup 自行处理。
2.一旦子元素有调用这个requestDisallowInterceptTouchEvent(true) 方法,那么此 ViewGroup 将无法拦截除 DOWN 以外的其他事件。
1.1.外部拦截法:
顾名思义,就是直接对外部的ViewGroup进行拦截处理,这块处理的话就是采用1的方法,即直接重写onInterceptTouchEvent,然后子View处理剩余的事件,这块主要有以下几点:
1.父类不能拦截ACTION_DOWN,也就是说ACTION_DOWN的时候必须返回false,就是不拦截
2.父类在ACTION_MOVE的时候根据需求,判断是否拦截。
3.ACTION_UP事件建议返回false或者super.onInterceptTouchEvent
,因为如果已经拦截的话,那么并不会调用onInterceptTouchEvent
方法再次询问。如果不拦截,而且返回true,子View可能就无法触发onClick等相关事件。
实现:
private boolean isIntercept;
private boolean isSolve;//是否完成了拦截判断,如果决定拦截,那么同系列事件就不能设置为不拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mPointGapF.x = ev.getX();
mPointGapF.y = ev.getY();
return false;//down的时候拦截后,就只能交给自己处理了
case MotionEvent.ACTION_MOVE:
if (!isSolve) {//是否已经决定拦截/不拦截?
isIntercept = (Math.abs(ev.getX() - mPointGapF.x) > Math.abs(ev.getY() - mPointGapF.y)*2);//如果是左右滑动,且水平角度小于30°,就拦截
isSolve = true;
}
return isIntercept;//如果是左右滑动,就拦截
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
scrollBy((int) (mPointGapF.x - ev.getX()), 0);
mPointGapF.x = ev.getX();
mPointGapF.y = ev.getY();
break;
}
return super.onTouchEvent(ev);
}
子View : 和子View没有多大关系,只需要处理自身的移动操作即可。
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mPointGapF.x = ev.getX();
mPointGapF.y = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
scrollBy(0, (int) (mPointGapF.y - ev.getY()));
mPointGapF.x = ev.getX();
mPointGapF.y = ev.getY();
break;
}
return true;
}
1.2.内部拦截
运用2的知识,
ViewGroup : 只需在onInterceptTouchEvent
MotionEvent.ACTION_DOWN时候不拦截,其他时候都需要拦截,否则父类的onTouchEvent
就不能处理任何事件了。
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
return false;//down的时候拦截后,就只能交给自己处理了
}
return true;//如果不拦截,父类的onTouchEvent方法就无事件可以处理。
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
scrollBy((int) (mPointGapF.x - ev.getX()), 0);
mPointGapF.x = ev.getX();
mPointGapF.y = ev.getY();
break;
}
return super.onTouchEvent(ev);
}
子View : 需要在ACTION_DOWN事件设置getParent().requestDisallowInterceptTouchEvent(true),并且在ACTION_MOVE的时候通过判断是否禁止父类的拦截。
private boolean isSolve;
private boolean isIntercept;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
isIntercept = false;
isSolve = false;
mPointGapF.x = ev.getX();
mPointGapF.y = ev.getY();
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if (!isSolve) {
isSolve = true;
isIntercept = (Math.abs(ev.getX() - mPointGapF.x) < Math.abs(ev.getY() - mPointGapF.y) * 2);
getParent().requestDisallowInterceptTouchEvent(isIntercept);
}
break;
}
return super.dispatchTouchEvent(ev);
}
2.案例2
2个滑动方向一致的滑动冲突,处理方法也跟案例1中的外部拦截方法一样,也是利用总结2中的知识点去解决:例如ScrollView与EditText的滑动冲突问题_z936689039的博客-CSDN博客
参考文章:
Android View的事件分发机制和滑动冲突解决_凶残的程序员-CSDN博客