最近看了看以前的bug和解决方法,发现自己在解决问题后很少去总结,现在发现下次再遇到的时候还是需要去查阅,在这里我还是把它拿出来总结了一下。当时在做项目的时候,是在ViewPager里面嵌套了ScrollView,导致了滑动十分的卡顿的bug,最后通过了ScrollView的onInterceptTouchEvent的重写,解决了这个bug。重写了ScrollView的onInterceptTouchEvent的代码:
private float mDownPosX = 0;
private float mDownPosY = 0;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownPosX = x;
mDownPosY = y;
break;
case MotionEvent.ACTION_MOVE:
final float deltaX = Math.abs(x - mDownPosX);
final float deltaY = Math.abs(y - mDownPosY);
if (deltaX > deltaY) {
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
首先记录了按下的坐标,然后根据计算x和y轴的移动距离大小来控制滑动时间,如果X轴移动的距离大于y轴的距离,
则返回false,不在执行ScrollView的onTouchEvent方法,也就拦截了ScrollView的上下滑动事件,奖滑动事件交给了ViewPager去处理。说到这里我就总结一下onInterceptTouchEvent和onTouchEvent方法吧。
一、onTouchEvent:
onTouchEvent是在view中定义的一个方法。处理传递到view 的手势事件。手势事件类型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL四种事件。一旦onTouchEvent方法被调用,并返回true则这个手势事件就结束了,并不会向下传递到子控件。
二、onInterceptTouchEvent:
onInterceptTouchEvent是在ViewGroup里面定义的。Android中的ViewGroup布局类都会继承此类的。onInterceptTouchEvent是用于拦截手势事件的,每个手势事件都会先调用onInterceptTouchEvent。
onInterceptTouchEvent()用于处理事件并改变事件的传递方向。返回值为false时事件会传递给子控件的onInterceptTouchEvent();返回值为true时事件会传递给当前控件的onTouchEvent(),而不在传递给子控件。由于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()处理。
下面在分析一下事件分发的机制,分发机制是由上往下的。有这样一个方法dispatchTouchEvent,该方法用来进行事件的分发,即无论ViewGroup或者View的事件,都是从这个方法开始的。然后就会执行上面的操作,直到这个事件被消耗。通过源代码的分析,大体是这样的:如果一个事件传递到了ViewGroup处,首先会判断当前ViewGroup是否要拦截事件,即调用onInterceptTouchEvent()方法;如果返回true,则表示ViewGroup拦截事件,那么ViewGroup就会调用自身的onTouchEvent来处理事件;如果返回false,表示ViewGroup不拦截事件,此时事件会分发到它的子View处,即调用子View的dispatchTouchEvent方法,如此反复直到事件被消耗掉。