Android 嵌套滑动冲突的处理
2019-08-21 本文已影响0人
halo_0b54
移动开发中滑动冲突很常见,也有多种处理方式,今天谈下我现在的处理策略(基本和系统处理策略一致)
最常见的滑动冲突:
一 上下拖动条,在左右可滑动的父组件里面。 手指放下到底是滑动拖动条还是父组件?
二 左右拖动条 ,在 上下可滑动的父组件里面,谁先滑动?你先滑完我再滑?
解决方案:观察手机系统组件 ,比如负一屏下面的亮度条,它是一个父控件上下滑动自己却左右滑动的控件,一般的厂商怎么处理的?它是通过观察在手放下的第一个动作,上下或者左右滑动来确定接下来抬手之前是左右滑动还是上下滑动的行为,如果左右滑动那下面抬手之前都是滑动你的亮度条(子空间);如果上下滑动那么下面抬手之前就是执行父控件的滑动了。
下面举个例子:
这里有一个可以上下滑动的View VerticalBar(随便写的一个) 我把它放在水平的RecycleView的里itemView里面 那么就造成了它在竖直方向上的滑动与RecycleView本身在水平滑动方向的冲突。如何解决,上面已经有粗略的方案了
image我们处理的逻辑都在 VerticalBar 的onTouchEvent里面
@Override
public boolean onTouchEvent(MotionEvent event) {
//忽略此处。。。
switch (event.getAction()) {
case MotionEvent.ACTION_UP: //up事件 釋放 此次滑动结束
setProgress((int) progress);
getParent().requestDisallowInterceptTouchEvent(false);
veticalDrad = false;
case MotionEvent.ACTION_CANCEL://cancle 事件 释放 此次滑动结束
veticalDrad = false;
break;
case MotionEvent.ACTION_DOWN: //事件开始 先请求父组件不拦截接下来的事件
downY = event.getY(); //记录此次事件一开始的坐标
getParent().requestDisallowInterceptTouchEvent(true); //先请求父组件不拦截接下来的事件
return true;
case MotionEvent.ACTION_MOVE: //!important
if (veticalDrad) { //如果已经判断是上下滑动事件 直接上下滑动得了
setProgress((int) progress);
getParent().requestDisallowInterceptTouchEvent(true);
} else { //当前状态不是正在上下滑动事件
if (Math.abs(event.getY() - downY)
>= ViewConfiguration.get(getContext()).getScaledTouchSlop() * 2) { //判断down的点与当前触摸点在y方向上的位移是否大於最小偏移量
setProgress((int) progress);
getParent().requestDisallowInterceptTouchEvent(true);
veticalDrad = true; //标记當前滑動是上下滑動事件
} else {//标记當前滑動非 上下滑動事件,把事件還給父控件
getParent().requestDisallowInterceptTouchEvent(false);
veticalDrad = false;
}
}
break;
//
}
return super.onTouchEvent(event);
}
解释一下:从down事件开始 请求父控件不拦截事件 ,因为现在还判断不出来到底是要向上滑动还是向下滑动,第一次move才能分辨处理 。所以在move时用当前坐标(y方向)与down事件时保存的坐标计算差值与最小滑动量比较,大于最小值则判定当前为竖直方向上滑动,继续请求不拦截事件,并标记(veticalDrad) 防止下次进来move事件又判断一遍,否则
getParent().requestDisallowInterceptTouchEvent(false);
veticalDrad = false;
释放接下来的事件给父控件,自己不会上下滑动了。
up cancle 事件逻辑虽然简单 但是 记得 释放状态啊!
项目地址 https://gitee.com/hailinnew/providerapp/tree/master/scrollconflictdemo
上动图