Android滑动冲突解决

来源:互联网 发布:趣图制作软件 编辑:程序博客网 时间:2024/04/30 04:24
android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解。 
一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP
当 屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是 ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?我只能很肯定的对你说不一定。呵呵,为什么呢?看看下面我的调查结果你 就明白了。
android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev)  这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent

当 TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由  dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如 果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。


让子先处理的方法是 从写父的onInterceptTouchEvent事件并返回false

public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;

    }

所以,如果我们最外面是一个ScrollView,里面又有一个Viewpager或者水平滑动的广告,这个时候默认他们就会产生冲突,当你在子View上水平滑动,如果不是非常标准的水平滑动,就会使外面的ScrollView垂直滑动,或者有跳动的感觉,这些都是滑动冲突导致的,那怎么解决呢?

按照上面的思路,最外面的ScrollView首先会接收到滑动事件,如果对这个滑动进行判断,如果是水平的话,就把这个滑动事件返回给自己的子View来出来,只有垂直滑动才给自己的onTouchEvent来处理即可,所以我们需要重写ScrollView的onInterceptTouchEvent方法,代码如下:

/** * 能够兼容ViewPager的ScrollView * @Description: 解决了ViewPager在ScrollView中的滑动反弹问题 */public class ScrollViewExtend extends ScrollView {    // 滑动距离及坐标    private float xDistance, yDistance, xLast, yLast;    public ScrollViewExtend(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                xDistance = yDistance = 0f;                xLast = ev.getX();                yLast = ev.getY();                break;            case MotionEvent.ACTION_MOVE:                final float curX = ev.getX();                final float curY = ev.getY();                                    xDistance += Math.abs(curX - xLast);                yDistance += Math.abs(curY - yLast);                xLast = curX;                yLast = curY;                                    if(xDistance > yDistance){                    return false;                }        }        return super.onInterceptTouchEvent(ev);    }}
本文参考:

http://blog.sina.com.cn/s/blog_9bb108790101aydx.html

http://glblong.blog.51cto.com/3058613/1307717

0 0