您的位置:首页 > 其它

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

2017-12-20 00:00 591 查看
------由于种种原因,本文废话较多,代码较少,可根据需求判定是否需要深入阅读。

(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;
}
});
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐