PullToRefreshView嵌套在ViewPager中的滑动冲突解决

【情景】

公司需要实现这么一个效果:
首先是一个可以左右滑动的ViewPager,当中的每个页面都有一个listView,而且需要实现下拉刷新功能。
这里写图片描述

【想法】

关于下拉刷新,直接使用GitHub上面的开源项目Android-PullToRefresh,毕竟使用起来很方便。

关于ViewPager,嵌套Fragment实现左右滑动,很传统的用法,没有什么多说的。

【问题1】

当我按照想法写出来后,基本实现了功能,但是有一个小bug,具体情况是这样的:

1、当我手指在ListView的Item上进行左右滑动的时候,并不能触发ViewPager的左右滑动切换。

2、当我手指在空白处或者在Item的分割线上进行滑动,才可以触发ViewPager的切换。

3、当我手指在ListView的Item上进行左右滑动的时候,有时会触发Item的点击事件(和滑动距离、速度有关)。

【分析1】

很明显是滑动冲突,而且第三点尤为重要,也就是说我进行左右滑动的时候,ViewPager并没有拦截该滑动事件,而是传递给了Item,Item拦截了后触发了点击操作。

【解决1】

因为用到了第三方库,为了其他地方使用时的安全稳定,我没有进行修改PullToRefreshListView,而是修改了ViewPager,使得当我进行左右滑动的时候它可以拦截并消费事件。

代码如下:

public class ViewPage extends ViewPager {
    private int lastX;
    private int lastY;

    public ViewPage(Context context) {
        super(context);
    }

    public ViewPage(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        boolean intercepted = false;

        int x = (int) ev.getX();
        int y = (int) ev.getY();

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //默认不拦截down事件,否则子view将无法收到事件
                intercepted = false;
                break;
            case MotionEvent.ACTION_MOVE:

                int deltaX = x - lastX;
                int deltaY = x - lastY;//未使用到

                //如果水平位移大于30,则拦截
                if (Math.abs(deltaX) > 30) {
                    intercepted = true;
                } else {
                    intercepted = false;
                }

                break;
            case MotionEvent.ACTION_UP:
                intercepted = false;
                break;
        }

        lastX = x;
        lastY = y;

        return intercepted;
    }
}

【结果1】

很出乎意料的是,这次事情变得更加严重了。无论我怎么滑,ViewPager都不能左右切换了。

【分析2】

我试了试,在空白处滑动也没有效果。

我坚信解决思路是没有问题的。

忽然间想起在ViewPager中嵌套ListView时,是不需要进行滑动冲突的处理的,因为ViewPager内部已经帮我们处理了这个冲突。

所以我无法在空白处滑动的原因很简单,就是我抛弃了ViewPager的滑动冲突的处理结果。

【解决2】

最后的返回结果中,如果我自己判断需要拦截或者ViewPager自己判断出需要拦截时,都需要进行拦截。代码如下:

public class ViewPage extends ViewPager {
    private int lastX;
    private int lastY;

    public ViewPage(Context context) {
        super(context);
    }

    public ViewPage(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        boolean intercepted = false;

        int x = (int) ev.getX();
        int y = (int) ev.getY();

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                intercepted = false;
                break;
            case MotionEvent.ACTION_MOVE:

                int deltaX = x - lastX;
                int deltaY = x - lastY;

                Log.e("ViewPage", "deltaX=" + Math.abs(deltaX) + ",deltaY=" + Math.abs(deltaY));

                if (Math.abs(deltaX) > 30) {
                    intercepted = true;
                } else {
                    intercepted = false;
                }

                break;
            case MotionEvent.ACTION_UP:
                intercepted = false;
                break;
        }

        lastX = x;
        lastY = y;

        //只修改了最后的返回结果
        //ViewPager自己处理了滑动冲突事件,所以如果viewPager自己确认拦截的话,也需要拦截。不能丢弃事件。
        return intercepted || super.onInterceptTouchEvent(ev);
    }
}

【结果2】

运行后试了试,果然解决了。特此记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值