ScrollView、SwipeRefreshLayout、ListView、RecyclerView等控件解决滑动冲突

        ------由于种种原因,本文废话较多,代码较少,可根据需求判定是否需要深入阅读。

(1)需求场景

ScrollView里面放了具备横向滑动的东西,进度条啊、横向的列表啊、banner等

ScrollView里面放好几层的LIstView、RecyclerView(其实非常不推荐这样做)

各种纵向横向的带滑动的东西交叉使用

(2)解决方案

滑动、拖动的权限本来是大家都有的,把它私有化就好了,具体的私有化过程就是不给ScrollView滑动,不给LIstView下滑,不给Seekbar拖动,差不多就是这个意思。

再详细一点,就是吧具体的相关的某些控件的onTouchEven事件给屏蔽了,核心在这个方法:
requestDisallowInterceptTouchEvent()

onTouchEven这个方法还有两个小伙伴需要了解一下(dispatchTouchEvent、OnInterceptTouchEven),他们之间的故事还是挺精彩的,也不多介绍,可以去看下别人的博客,这里有个连接:https://www.cnblogs.com/neil-zhao/p/3778094.html

其实大概意思就是,dispatchTouchEvent是有限执行,且用requestDisallowInterceptTouchEvent是不能屏蔽掉的,onTouchEven则是这些可拖动可下滑的控件滑动的关键,所以只要吧父容器的onTouchEven屏蔽掉的话,就能达到横向滑动的时候禁止纵向滑动的效果。

需要做的就是重写控件的onTouchEven方法,在按下的时候或者是滑动超出某个范围的时候禁止列表下滑,可以看下简单的代码:

 /**
     * 设置需要屏蔽触摸事件的控件(横向移动幅度大于60像素的时候会促发屏蔽效果)
     * @param view
     */
    public void stopTouchShield(final View view){
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                if (action == MotionEvent.ACTION_DOWN) {
                    // 记录点击到ViewPager时候,手指的X坐标
                    lastX = event.getX();
                }
                if (action == MotionEvent.ACTION_MOVE) {
                    float x=event.getX()-lastX;
                    if(x<0){
                        x*=-1;
                    }
                    if(x>4f){
                        recyclerView.requestDisallowInterceptTouchEvent(true);
                    }
                }
                if (action == MotionEvent.ACTION_UP) {
                    // 用户抬起手指,恢复父布局状态
                    recyclerView.requestDisallowInterceptTouchEvent(false);
                }
                return false;
            }
        });
    }

(3)这事还有坑

我用了很多下拉刷新的组件,很多用的都不太舒服,滑动回弹的效果不是我喜欢的,所以自己手撸了一个下拉刷新的,还有一个ScrollView,写这两个东西的时候,如果是重写控件的onTouchEven方法的时候,总是会出现莫名其妙的拖不动或者是回弹出错的毛病,所以重写的时候基本上不懂onTouchEven方法,而是改为重写dispatchTouchEvent,然后就一帆风顺了。

没有去深入研究Android的源码,有个研究过的大神在一篇博客里面说过,如果requestDisallowInterceptTouchEvent不生效的话,就是跟dispatchTouchEvent有关系,dispatchTouchEvent在搞某种操作的时候会把requestDisallowInterceptTouchEvent设置的参数重置,大概是这个意思,具体描述我也找不到那篇博客了,反正可以确定的是,如果requestDisallowInterceptTouchEvent不生效,那就是跟dispatchTouchEvent有关系。

通过我手撸下拉刷新的经验,可以重写ScrollView、RecyclerView等控件的dispatchTouchEvent方法,在需要屏蔽掉下滑操作的时候,屏蔽掉super.dispatchTouchEvent操作,然后再结合requestDisallowInterceptTouchEvent来使用,应该没问题。

我这里的写法就是,重写的时候提供屏蔽的方法,然后多加一个boolean变量用于标识是否需要屏蔽掉dispatchTouchEvent,然后在重写的dispatchTouchEvent的时候加上这个boolean变量判定是否需要执行后续的操作。

习惯性贴一下代码,不保证适用:


    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if(!isTouchShield){
            //不屏蔽滑动事件
            return super.dispatchTouchEvent(event);
        }
    }


    /**
     * 设置需要屏蔽触摸事件的控件(横向移动幅度大于60像素的时候会促发屏蔽效果)
     * @param view
     */
    public void stopTouchShield(final View view){
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                if (action == MotionEvent.ACTION_DOWN) {
                    // 记录点击到ViewPager时候,手指的X坐标
                    lastX = event.getX();
                }
                if (action == MotionEvent.ACTION_MOVE) {
                    float x=event.getX()-lastX;
                    if(x<0){
                        x*=-1;
                    }
                    if(x>4f){
                        recyclerView.requestDisallowInterceptTouchEvent(true);
                        isTouchShield(true);
                    }
                }
                if (action == MotionEvent.ACTION_UP) {
                    // 用户抬起手指,恢复父布局状态
                    recyclerView.requestDisallowInterceptTouchEvent(false);
                    isTouchShield(false);
                }
                return false;
            }
        });
    }

 

转载于:https://my.oschina.net/u/1462828/blog/1592769

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值