*****
**事件分发的使用**
[TOC=6]
# 1.解决事件滑动冲突的思路及方法
## 1.1常见的三种情况
第一种情况,滑动方向不同
![](http://ww1.sinaimg.cn/mw690/9fe4afa0gw1f95qa1uuxuj20g00ca0sz.jpg)
第二种情况,滑动方向相同
![](http://ww4.sinaimg.cn/mw690/9fe4afa0gw1f95q97u2nlj20vc0i7761.jpg)
第三种情况,上述两种情况的嵌套
![](http://ww2.sinaimg.cn/mw690/9fe4afa0gw1f95qao07c2j20dw0i3q3q.jpg)
## 1.2 解决思路
看了上面三种情况,我们知道他们的共同特点是父View 和子View都想争着响应我们的触摸事件,但遗憾的是我们的触摸事件 同一时刻只能被某一个View或者ViewGroup拦截消费,所以就产生了滑动冲突?那既然同一时刻只能由某一个View或者ViewGroup消费拦截,那我们就只需要 决定在某个时刻由这个 View 或者 ViewGroup 拦截事件,另外的 某个时刻由 另外一个 View 或者 ViewGroup 拦截事件,不就OK了吗?综上,正如 在 《Android开发艺术》 一书提出的,总共 有两种解决方案
以下解决思路来自于 《Android开发艺术》 书籍
下面的两种方法针对第一种情况(滑动方向不同),父View是上下滑动,子View是左右滑动的情况。
## 1.3 外部解决法
从父View着手,重写onInterceptTouchEvent方法,在父View需要拦截的时候拦截,不要的时候返回false,为代码大概 如下
~~~
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownPosX = x;
mDownPosY = y;
break;
case MotionEvent.ACTION_MOVE:
final float deltaX = Math.abs(x - mDownPosX);
final float deltaY = Math.abs(y - mDownPosY);
// 这里是够拦截的判断依据是左右滑动,读者可根据自己的逻辑进行是否拦截
if (deltaX > deltaY) {
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
~~~
## 1.4 内部解决法
从子View着手,父View先不要拦截任何事件,所有的事件传递给 子View,如果子View需要此事件就消费掉,不需要此事件的话就交给 父View处理。
实现思路 如下,重写子 View的dispatchTouchEvent方法,在Action\_down 动作中通过方法 requestDisallowInterceptTouchEvent(true) 先请求 父 View不要拦截事件,这样保证子 View 能够接受到 Action\_move 事件,再在 Action\_move 动作中根据自己的逻辑是否要拦截事件,不需要拦截事件的话再交给 父 View 处理。
~~~
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getRawX();
int y = (int) ev.getRawY();
int dealtX = 0;
int dealtY = 0;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
dealtX = 0;
dealtY = 0;
// 保证子View能够接收到Action_move事件
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
dealtX += Math.abs(x - lastX);
dealtY += Math.abs(y - lastY);
Log.i(TAG, "dealtX:=" + dealtX);
Log.i(TAG, "dealtY:=" + dealtY);
// 这里是够拦截的判断依据是左右滑动,读者可根据自己的逻辑进行是否拦截
if (dealtX >= dealtY) {
getParent().requestDisallowInterceptTouchEvent(true);
} else {
getParent().requestDisallowInterceptTouchEvent(false);
}
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
~~~
# 2. ScrollView嵌套ListView或GridView滑动冲突解决方案
开发过程中经常会遇到使用scrollview嵌套listview或gridview的情况,这时由于scrollview拦截消费了滑动事件,所以在listview或gridview区域滑动时该区域无法滑动,而是scrollview整体滑动。
正确的处理应该是当焦点在listview或gridview区域该区域滑动,在区域外则scrollview滑动。
想要解决这个问题,加上如下代码即可:
~~~
listView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
scrollView.requestDisallowInterceptTouchEvent(true);
return false;
}
}
~~~
~~~
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
~~~
# 3. ViewPager嵌套ViewPager滑动冲突解决方案
## 内部解决法
从子View ViewPager着手,重写 子View的 dispatchTouchEvent方法,在子 View需要拦截的时候进行拦截,否则交给父View处理,代码如下
~~~
public class ChildViewPager extends ViewPager {
private static final String TAG = "xujun";
public ChildViewPager(Context context) {
super(context);
}
public ChildViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int curPosition;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
curPosition = this.getCurrentItem();
int count = this.getAdapter().getCount();
Log.i(TAG, "curPosition:=" +curPosition);
// 当当前页面在最后一页和第0页的时候,由父亲拦截触摸事件
if (curPosition == count - 1|| curPosition==0) {
getParent().requestDisallowInterceptTouchEvent(false);
} else {//其他情况,由孩子拦截触摸事件
getParent().requestDisallowInterceptTouchEvent(true);
}
}
return super.dispatchTouchEvent(ev);
}
}
~~~
# 4. ScrollView嵌套ViewPager滑动冲突解决方案(了解)
## 4.1 外部解决
从 父View ScrollView着手,重写 OnInterceptTouchEvent方法,在上下滑动的时候拦截事件,在左右滑动的时候不拦截事件,返回 false,这样确保子View 的dispatchTouchEvent方法会被调用,代码 如下
~~~
/**
* @ explain:这个ScrlloView不拦截水平滑动事件,
* 是用来解决 ScrollView里面嵌套ViewPager使用的
*/
public class VerticalScrollView extends ScrollView {
public VerticalScrollView(Context context) {
super(context);
}
public VerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(21)
public VerticalScrollView(Context context, AttributeSet attrs, int defStyleAttr, int
defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private float mDownPosX = 0;
private float mDownPosY = 0;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownPosX = x;
mDownPosY = y;
break;
case MotionEvent.ACTION_MOVE:
final float deltaX = Math.abs(x - mDownPosX);
final float deltaY = Math.abs(y - mDownPosY);
// 这里是否拦截的判断依据是左右滑动,读者可根据自己的逻辑进行是否拦截
if (deltaX > deltaY) {// 左右滑动不拦截
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
}
~~~
## 4.2 内部解决
通过requestDisallowInterceptTouchEvent(true)方法来影响父View是否拦截事件,我们通过重写ViewPager的 dispatchTouchEvent()方法,在左右滑动的时候请求父View ScrollView不要拦截事件,其他的时候由子View 拦截事件
~~~
/**
* @ explain:这个 ViewPager是用来解决ScrollView里面嵌套ViewPager的 内部解决法的
*/
public class MyViewPager extends ViewPager {
private static final String TAG = "xujun";
int lastX = -1;
int lastY = -1;
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getRawX();
int y = (int) ev.getRawY();
int dealtX = 0;
int dealtY = 0;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
dealtX = 0;
dealtY = 0;
// 保证子View能够接收到Action_move事件
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
dealtX += Math.abs(x - lastX);
dealtY += Math.abs(y - lastY);
Log.i(TAG, "dealtX:=" + dealtX);
Log.i(TAG, "dealtY:=" + dealtY);
// 这里是否拦截的判断依据是左右滑动,读者可根据自己的逻辑进行是否拦截
if (dealtX >= dealtY) { // 左右滑动请求父 View 不要拦截
getParent().requestDisallowInterceptTouchEvent(true);
} else {
getParent().requestDisallowInterceptTouchEvent(false);
}
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
}
~~~
- 咨询项目实战
- 第一单元 HTTP协议
- 1.1 OSI七层模型
- 1.2 HTTP协议(重点)
- 1.3 HTTPS协议(了解)
- 1.4 TCP/IP协议扩展
- 1.5 WebService简介及实战(无接口)
- 1.6 课后练习
- 第二单元 HTTPURLConnection
- 2.1 ANR
- 2.2 网络判断
- 2.3 HTTPURLConnection
- 2.4 课后练习
- 第三单元 AsyncTask
- 3.1 AsyncTask概述
- 3.2 AsyncTask基本使用
- 3.3 课后练习
- 第四单元 图片异步加载
- 4.1 图片异步加载概述
- 4.2 LruCache
- 4.3 DiskLRUCache
- 4.4 图片三级缓存概述
- 4.5 封装图片加载缓存框架
- 第五单元 ListView多条目
- 5.1 ListView多条目概述
- 5.2 ListView多条目的使用
- 第六单元 ListView实现下拉刷新上拉加载
- 6.1 下拉刷新和上拉加载更多
- 6.2 XListView概述
- 6.3 XListView的使用
- 第七单元 封装网络框
- 7.1 封装网络框架概述
- 7.2 网络框架的封装
- 第八单元 项目介绍
- 8.1 公司项目团队架构简介
- 8.2 项目文档及项目流程介绍
- 8.3 项目管理
- 8.4 项目开发
- 第九单元 项目框架搭建
- 9.1 基类封装概述
- 9.2 Application中初始化配置
- 9.3 项目中的工具类
- 9.4 封装网络请求框架
- 9.5 封装图片异步缓存框架
- 第十单元 搭建UI框架1
- 10.1 侧滑菜单概述
- 10.2 主界面框架搭建
- 第十一单元 搭建UI框架2
- 11.1 TabLayout的概述
- 11.2 TabLayout的使用
- 第十二单元 图片上传
- 12.1 图片上传概述
- 12.2 图片上传的实现
- 第十三单元 PullToRefresh
- 13.1 PullToRefresh概述
- 13.2 PullToRefresh的使用
- 13.3 缓存业务实现思路
- 第十四单元 事件分发及滑动冲突
- 14.1 事件分发概述
- 14.2 事件分发流程
- 14.3 事件分发的使用
- 第十五单元 传感器的基本使用
- 15.1 传感器概述
- 15.2 传感器的使用
- 第十六单元 HTML与CSS复习
- 16.1 HTML
- 16.2 CSS
- 第十七单元 js复习
- 17.1 js基础语法
- 17.2 js数组和内置对象
- 17.3 js常用事件
- 17.4 js对象模型
- 17.5 js 正则表达式
- 第十八单元 WebView
- 18.1 WebView 概述
- 18.2 WebView的使用
- 18.3 WebView与js交互
- 第十九单元 项目案例
- 项目概述
- 第二十单元 项目答辩
- 周考
- 第一周周考
- 第二周周考
- 第三种周考
- 月考
- 接口文档