1.滑动冲突原因:

当有内外两层View同时可以滑动的时候,这个时候就会产生滑动冲突。

2.常见的冲突场景:

场景1:

场景2:

场景3:

4.解决方法种类:

(1)外部拦截法:

针对场景1,我们可以发现外部和内部的滑动方向不一样也就是说只要判断当前dy和dx的大小,如果dy>dx,那么当前就是竖直滑动,否则就是水平滑动。明确了这个我就就可以根据当前的手势开始拦截了。从view的事件分发中我们了解点击事件的分发顺序是 通过父布局分发,如果父布局没有拦截,即onInterceptTouchEvent返回false,才会传递给子View。所以我们就可以利用onInterceptTouchEvent()这个方法来进行事件的拦截。

  public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY(); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
intercepted = false;
break;
}
case MotionEvent.ACTION_MOVE: {
if(父容器拦截的规则){
intercepted=true;
}else{
intercepted=false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept=x;
mLastYIntercept=y;
return intercepted;
}

上面的代码差多就是外部拦截的通用模板了,在onInterceptTouchEvent方法中,

首先是ACTION_DOWN这个事件,父容器必须返回false,即不拦截事件,因为一旦父容器拦截了ACTION_DOWN这个事件,那么后续的ACTION_MOVE和ACTION_UP事件将直接交给父容器处理,这个时候事件没法继续传递给子元素了;

然后是ACTION_MOVE这个事件,这个事件可以根据需要决定是否拦截,如果父容器需要拦截就返回true,否则返回false;

最后是ACTION_UP这个事件,这里必须返回false,因为这个事件本身也没有太多意义。

so场景一的外部拦截解决方法:

 public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY(); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
intercepted = false;
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX=x-mLastXIntercept;
int deltaY=y=mLastYIntercept;
if(Math.abs(deltaX)>Math.abs(deltaY)){
intercepted=true;
}else{
intercepted=false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept=x;
mLastYIntercept=y;
return intercepted;
}

场景二的外部拦截方法:

 public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY(); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastYIntercept=y;
intercepted = super.onInterceptTouchEvent(event);
break;
}
case MotionEvent.ACTION_MOVE: {
if(listView.getFirstVisiblePosition()==0 &&y>mLastYIntercept){
intercepted=true;
}else if(listView.getLastVisiblePosition()==listView.getCount-1&&y <mLastYIntercept){
intercepted=false;
break;
}
intercepted = false;
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept=x;
mLastYIntercept=y;
return intercepted;
}

(2)内部拦截法

内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器去处理

(android系统中,一次点击事件是从父view传递到子view中,每一层的view可以决定是否拦截并处理点击事件或者传递到下一层,如果子view不处理点击事件,则该事件会传递会父view,由父view去决定是否处理该点击事件。在子view可以通过设置此方法去告诉父view不要拦截并处理点击事件,父view应该接受这个请求直到此次点击事件结束)需要用到方法requestDisallowInterceptTouchEvent。

 内部拦截通用模板:

  

 public boolean onInterceptTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY(); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
parent.requestDisallowInterceptTouchEvent(true); //父布局不要拦截此事件
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX=x-mLastXIntercept;
int deltaY=y=mLastYIntercept;
if(父容器需要拦截的事件){
parent.requestDisallowInterceptTouchEvent(false); //父布局需要要拦截此事件
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept=x;
mLastYIntercept=y;
return super.dispathTouchEvent(event);
}

so 场景二的内部拦截解决方法:

 //拦截除了Down事件以外的其他方法:
public boolean onInterceptTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int action = event.getAction();
if(action == MotionEvent.ACTION_DOWN){
mLastXIntercept=x;
mLastYIntercept=y;
return super.dispathTouchEvent(event);
}else{
return true;
}
}

场景三建议使用内部拦截方法比较方便

最新文章

  1. Redis实战阅读笔记——第一章
  2. 商业智能SAAS走向中小企业
  3. 【原创】.NET读写Excel工具Spire.Xls使用(2)Excel文件的控制
  4. hdu 2102 A计划-bfs
  5. 转:Delphi和Office程序开发 --不错可查阅
  6. VS2013相关资料
  7. hibernate中有时候复杂删除有时候可以拆分为两个语句
  8. poj1016
  9. Spring、XML配置AOP
  10. 读 《我为什么放弃Go语言》 有感
  11. 只查看tomcat进程,不包括grep
  12. Hi Java!!!---来自十八岁的程序员随笔
  13. Android视频录制从不入门到入门系列教程(一)————简介
  14. Android使用Mob ShareSDK 分享不同平台
  15. C#基础知识之静态和非静态
  16. pygame-KidsCanCode系列jumpy-part12-platform图片
  17. windows更改Jupyter Notebook工作的目录
  18. C++ 常见术语及解释
  19. ubuntu,day1基础命令,shutdown,man,touch,rm,mv,cp,stat,locale,apt,date,tzselect,cal,快捷方式,echo,查看文件
  20. OpenBLAS简介及在Windows7 VS2013上源码的编译过程

热门文章

  1. JS规则 给变量取个名字(变量命名) 必须以字母、下划线或美元符号开头;区分大小写;不允许使用JS关键字或保留字
  2. bind()的模拟实现
  3. Func-Chain.js 另一种思路的javascript异步编程解决方案
  4. 学习 debug
  5. Android开发 LevelListDrawable详解
  6. 二分图——最小覆盖poj2226
  7. 用python获取ip信息
  8. 13_数据的划分和介绍之sklearn数据集
  9. js 使用script或template标签:分离js代码template中的HTML元素
  10. java笔试之求int型正整数在内存中存储时1的个数