------因为种种缘由,本文废话较多,代码较少,可根据需求断定是否须要深刻阅读。html
ScrollView里面放了具有横向滑动的东西,进度条啊、横向的列表啊、banner等ide
ScrollView里面放好几层的LIstView、RecyclerView(其实很是不推荐这样作)布局
各类纵向横向的带滑动的东西交叉使用spa
滑动、拖动的权限原本是你们都有的,把它私有化就行了,具体的私有化过程就是不给ScrollView滑动,不给LIstView下滑,不给Seekbar拖动,差很少就是这个意思。code
再详细一点,就是吧具体的相关的某些控件的onTouchEven事件给屏蔽了,核心在这个方法:
requestDisallowInterceptTouchEvent()htm
onTouchEven这个方法还有两个小伙伴须要了解一下(dispatchTouchEvent、OnInterceptTouchEven),他们之间的故事仍是挺精彩的,也很少介绍,能够去看下别人的博客,这里有个链接:https://www.cnblogs.com/neil-zhao/p/3778094.htmlblog
其实大概意思就是,dispatchTouchEvent是有限执行,且用requestDisallowInterceptTouchEvent是不能屏蔽掉的,onTouchEven则是这些可拖动可下滑的控件滑动的关键,因此只要吧父容器的onTouchEven屏蔽掉的话,就能达到横向滑动的时候禁止纵向滑动的效果。事件
须要作的就是重写控件的onTouchEven方法,在按下的时候或者是滑动超出某个范围的时候禁止列表下滑,能够看下简单的代码:get
/** * 设置须要屏蔽触摸事件的控件(横向移动幅度大于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; } }); }
我用了不少下拉刷新的组件,不少用的都不太舒服,滑动回弹的效果不是我喜欢的,因此本身手撸了一个下拉刷新的,还有一个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; } }); }