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

Android中View的事件分发和拦截机制

2015-10-16 00:12 513 查看
博客转移到个人站点:

http://www.wangchengmeng.club/2018/02/04/Android%E4%B8%ADView%E7%9A%84%E4%BA%8B%E4%BB%B6%E5%88%86%E5%8F%91%E5%92%8C%E6%8B%A6%E6%88%AA%E6%9C%BA%E5%88%B6/

欢迎来吐槽

1.关系到事件分发和拦截机制的三个方法

1.dispatchTouchEvent(MotionEvent event)方法
2.onInterceptTouchEvent(MotionEvent event)方法
3.onTouchEvent(MotionEvent event)方法


2.dispatchTouchEvent(MotionEvent event)分发事件

*该方法主要是用来事件分发的,返回值有三种情况

1.返回 super.dispatchTouchEvent(ev)
会将事件分发下去
2.返回true
不会将事件分发下去,自己就调用当前View的onTouchEvent方法处理了
3.返回false
不会将事件分发下去

*该方法内部其实自己调用了onInterceptTouchEvent方法,进行事件拦截,默认情况下不会拦截事件,将事件放行。

*子View可以申请父View进行拦截/不拦截,其实也就是在内部判断是否调用onInterceptTouchEvent进行事件拦截。
1.getParent().requestDisallowIntercept(true)
申请父View不拦截,那就执行自己的onTouchEvent事件

2.getParent().requestDisallowIntercept(false)
申请拦截,父View将其事抢夺过来,执行父View的onTouchEvent事件


3.onInterceptTouchEvent(MotionEvent event)拦截事件

三种返回值:

1.true
将事件拦截,不在分发下去,执行当前View的onTouchEvent
2.false
将事件方法(默认就是放行),那子View会继续分发事件执行disPatchTouchEvent。
3. super.onInterceptTouchEvent(ev)
默认情况下不拦截


4.onTouchEvent(MotionEvent event)

是用来处理事件的,接收到分发的事件,就调用该方法去进行事件的处理

返回true,就不将事件回传给父View,自己消费掉
返回false和super.onTouchEvent(ev),将事件回传给父View,并由父View的的onTouchEvent来接收


5.Demo(案例)

1.两个ViewPager嵌套关系出现的问题。

当两个ViewPager嵌套的时候,(ViewPager自带滑动功能)在滑动内层(子)ViewPager的时候,在没有做处理的情况下,外层(父)的ViewPager会抢夺滑动事件,所以会出现,滑动子ViewPager的时候,父ViewPager滑动了,这种用户体验就很差

2.解决办法

1)自定义一个类继承ViewPager,作为内层的ViewPafder

2)复写onDispatchEvent(MptionEvent event)方法,

3)定义条件,在满足什么样条件下申请父View不拦截或者拦截
比如:在子ViewPager滑动到第一个页面并且从左往右滑动的时候,申请父View拦截,getParent().requestDisallowInterceptEvent(false),而子ViewPager默认到了第一个页面的时候,再继续向前一个不存在的页面是不能滑动的,这个时候父ViewPager就进行滑动,滑到子ViewPager最后一个页面并且继续从右往左滑动,同样的申请父View拦截。在其他情况下申请父View不拦截getParent().requestDisallowInterceptEvent(true),那么父ViewPager将不会个子ViewPager抢夺滑动事件,子ViewPager可以顺畅的滑动。

3.code(代码)

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {

/***
* 当多个view容器嵌套一起,事件分发机制会起冲突
* 比如当两个ViewPager嵌套使用的时候,子ViewPager滑动的时候父Viewpager可能抢夺事件,
* 这样滑动子ViewPager的时候,父ViewPager跟着滑动 这个时候我们只需要子ViewPager滑动,就可以
* 使用requestDisallowInterceptTouchEvent(true)
* 这个方法去申请父view容器的是否拦截,将其参数这是为true就是申请父view容器不拦截,不拦截子控件的事件,
* 那子控件就做自己的onTouchEvent事件,父view容器就不会抢夺事件了,
*
* 可以设置条件当子ViewPager滑动到第一个或者最后一个了,就可以申请拦截,那么子ViewPager不能滑动的时候
* 父ViewPager在子ViewPager申请拦截之后就可以拦截子ViewPager,然后自己执行onTouchEvent事件
*/

// 申请父控件不拦截
getParent().requestDisallowInterceptTouchEvent(true);

// 分析:
// 当滑动到第一个页面,而且从左往右滑动的时候,就申请拦截,让父ViewPager滑动
// 当滑动到最后一个页面的时候,而且从右往左滑动的时候,申请拦截
// 其他情况申请不拦截,让子Viewpager滑动

switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:// 按下

// 获取按下的X Y坐标
downX = ev.getX();
downY = ev.getY();

break;
case MotionEvent.ACTION_MOVE:// 移动
// 获取移动的X Y 坐标
float moveX = ev.getX();
float moveY = ev.getY();
float dX = downX - moveX;
float dY = downY - moveY;
// 如果Y轴方向移动,什么事情都不做,值关注横向滑动
if (Math.abs(dX) > Math.abs(dY)) {
// 表示横向移动
// 如果是当前页面不是第一个页面 并且是从右往左滑动,申请不拦截
if (getCurrentItem() != 0 && dX < 0) {

getParent().requestDisallowInterceptTouchEvent(true);

} else if (getCurrentItem() < getChildCount() - 1 && dX > 0) {
//申请不拦截
getParent().requestDisallowInterceptTouchEvent(true);

} else {
// 申请拦截
getParent().requestDisallowInterceptTouchEvent(false);
}
}else{
//纵向  申请拦截
getParent().requestDisallowInterceptTouchEvent(false);
}

break;

}
//依然还是走父View中去分发事件
return super.dispatchTouchEvent(ev);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息