您的位置:首页 > 移动开发 > Android开发

Android滑动冲突解决

2016-12-29 17:09 281 查看
1、滑动冲突的场景

(1) 外部滑动方向和内部滑动方向不一致;

(2) 外不滑动方向和内部滑动方向一致;

(3) 上边两种情况的集合

图解如下:



场景1: 主要是将viewpage和fragment配合使用所组成的滑动效果,主流应用几乎都会使用这个效果,在这个效果中可以通过左右滑动来切换页面,而每个页面内部都有listview,但是因为这种情况viewpage已经做了滑动冲突的处理,所以我们不用解决,如果我们采用的是scrollerview,那么我们就要解决滑动冲突。否则就会造成内外两层只有一层能狗滑动。场景三是slidermenu和viewpage,listview三种情况,看起来很复杂,但是可以分开来看。

2、滑动冲突的处理规则

对于场景一来说,我们可以根据水平滑动或者竖直滑动来拦截触发事件,根据滑动两个点之间的坐标就可以知道是水平滑动还是竖直滑动,我们可以根据华东路径和水平方向的夹角,也可以根据水平方向和竖直方向滑动的距离来判断,特殊情况下还可以根据水平或者竖直的速度差来判断。

对于场景二来说,比较摊位数,不弄用以上的方法来判断,他需要在业务上找到突破点,当处于某种状态时,需要响应用户的外部滑动,再摸种情况下需要响应用户的内部滑动,


3、滑动冲突的解决方法

(1)外部拦截法

就是所有的点击事件都要经过父控件的处理,如果父容器需要此事件就拦截,不需要此事件就不拦截,这样就可以解决滑动冲突的问题,这种方法比较适合于事件的分发机制,外部拦截法需要重写父容器的onintercepttouchevent方法,在内部做相应的拦截;伪代码如下:

// 父容器是否需要此事件
boolean state = false;
int mLastxintercept = 0;
int mLastintercept = 0;

@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:
if (state) {
intercepted = true;
} else {
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;

default:
break;
}
mLastX = x;
mLastY = y;
return intercepted;
}


这里需要考虑一种情况,就是当事件交由子元素进行处理,如果父容器在actionup 时返回了true,那么就会导致子元素无法收到actionup事件,这个时候子元素中的onclick事件将不会响应,但父容器比较特殊,当有一个事件被拦截,那么其他的事件都会交给他来处理,尽管onintercepttouchevent返回false;

(2)内部拦截法

这种方法就是父容器不拦截任何事件,事件全部交给子元素来处理,如果子元素需要就直接消耗掉,如果子元素不处理就交给父容器,这种方法和Android的事件分发不一致,需要配合requestdisallowintercepttouchevent方法才能正常工作,使用起来稍微复杂,伪代码如下所示:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
boolean consume = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
super.requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:

int deltax = x - mlastx;
int deltay = mLastY;
// 是否需要此事件
if (state) {
super.requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:

break;
default:
break;
}
mlastx = x;
mLastY = y;
return super.onInterceptTouchEvent(event);
}

上面是典型的代码内部拦截方法,当面对不同的策略时只需要修改里边的条件就行,其他的不需要改动也不能挨冻,除了子元素要处理外,父元素也要默认拦截了actiondown以外的其他事件,这样当子元素super.requestDisallowInterceptTouchEvent(false);时,父元素才能继续拦截所需要的事件。父元素不能拦截actiondown事件,是因为actiondown事件并不受flagdisallowintercept的影响,当父元素一旦拦截了actiondown事件,那么所有的事件都不能传到子元素中去。这样内部拦截就不能起作用了。父元素作如下修改:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

int action = ev.getAction();
if (action == MotionEvent.ACTION_DOWN) {
return false;

} else {
return true;
}
}

下一节我们将会用实列来演示和讲解view的滑动。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android