Android滑动冲突解决
2016-12-29 17:09
281 查看
1、滑动冲突的场景
(1) 外部滑动方向和内部滑动方向不一致;
(2) 外不滑动方向和内部滑动方向一致;
(3) 上边两种情况的集合
图解如下:
![](http://img.blog.csdn.net/20161229171152277?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjgyNzMwNTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
场景1: 主要是将viewpage和fragment配合使用所组成的滑动效果,主流应用几乎都会使用这个效果,在这个效果中可以通过左右滑动来切换页面,而每个页面内部都有listview,但是因为这种情况viewpage已经做了滑动冲突的处理,所以我们不用解决,如果我们采用的是scrollerview,那么我们就要解决滑动冲突。否则就会造成内外两层只有一层能狗滑动。场景三是slidermenu和viewpage,listview三种情况,看起来很复杂,但是可以分开来看。
2、滑动冲突的处理规则
对于场景一来说,我们可以根据水平滑动或者竖直滑动来拦截触发事件,根据滑动两个点之间的坐标就可以知道是水平滑动还是竖直滑动,我们可以根据华东路径和水平方向的夹角,也可以根据水平方向和竖直方向滑动的距离来判断,特殊情况下还可以根据水平或者竖直的速度差来判断。
对于场景二来说,比较摊位数,不弄用以上的方法来判断,他需要在业务上找到突破点,当处于某种状态时,需要响应用户的外部滑动,再摸种情况下需要响应用户的内部滑动,
![](http://img.blog.csdn.net/20161229173039951?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjgyNzMwNTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
3、滑动冲突的解决方法
(1)外部拦截法
就是所有的点击事件都要经过父控件的处理,如果父容器需要此事件就拦截,不需要此事件就不拦截,这样就可以解决滑动冲突的问题,这种方法比较适合于事件的分发机制,外部拦截法需要重写父容器的onintercepttouchevent方法,在内部做相应的拦截;伪代码如下:
这里需要考虑一种情况,就是当事件交由子元素进行处理,如果父容器在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的滑动。
(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的滑动。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件