当前位置:网站首页>根据热门面试题分析Android事件分发机制(二)---事件冲突分析处理
根据热门面试题分析Android事件分发机制(二)---事件冲突分析处理
2022-07-07 07:03:00 【光阴剑客】
(一)事件冲突概述
事件冲突一般发生在父view和子view的组合中,比如说viewpager和listview 的组合中。产生事件冲突的原因是一个事件(down,up,move)到来时,有时候我们希望是A view处理,但是却是B view处理。这样就导致了我们想处理事件的view收不到事件,不想处理事件的view收到了事件。而解决冲突就是我们通过viewGroup的onInterceptTouchEvent()方法去合理的分发事件,让想处理事件的view收到事件,不想处理的view躺平啥也不做。
(二)没有事件冲突的效果展示
(看看美女,再写代码~~)
言归正传,如上图所示,demo是由一个viewpager+listView的组合,我们发现在没有事件冲突的情况下,应该是既能左右滑动,也能上下滑动。为了演示,我们分别继承自viewpager和Listview,viewPager作为父view,重写它的onInterceptTouchEvent方法,listview作为子view,重写dispatchTouchevent.(需要的时候),demo的源码很简单,我会在文章末尾给出。
(说明:如果不重写onInterceptTouchEvent和listview的dispatchTouchevent方法,我们直接使用viewpager+listview组合会发现不会产生事件冲突,那是因为sdk里面已经解决了冲突,可以查看viewpager的源码)
模拟冲突的产生 :
情景1: 当我们在父view,也就是viewPager的onInterceptTouchEvent方法中直接返回true,拦截事件,这时候我们会发现我们只可以响应view pager的左右滑动,而不能响应listview的上下滑动,原因就是我们在父view直接拦截了事件,导致子view listview 收不到事件,无法响应事件。
情景2: 当我们在父view,也就是viewPager的onInterceptTouchEvent方法中直接返回false,不拦截事件,我们这时会发现,viewpager 不可以左右滑动,只可以上下滑动listview,这是因为viewpager不拦截事件,将事件分发给了子view处理,所以他无法响应自己的左右滑动事件。
(三)面试题:你遇到过滑动冲突吗?你是怎么处理的?
解析: 这时假如你自己遇到过,就答你遇到的冲突产生的情景,然后说下你的解决方法,如果你没有遇到过,就回答咱们本文中提到的viewpager+listview的场景。根据上面的内容总结下就可以,然后就是如何解决冲突的回答,这时候你可以回答有两种冲突解决方法:
方法一:在父view的onInterceptTouchEvent中解决冲突,代码如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//在父view中进行冲突处理,不需要子view实现dispatchTouchEvent方法
float x = ev.getX();//记录下x,y的初始值
float y = ev.getY();
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
super.onInterceptTouchEvent(ev);
//这里需要调用sdk中的viewpager中的
//onInterceptTouchEvent方法处理一些特殊问题
//不调用的话我们拦截了事件也无法响应滑动
return false;//不能拦截down事件,拦截了down
//事件,就无法收到后面的move,和up事件了
case MotionEvent.ACTION_MOVE:
float xDiff = Math.abs(x-mLastX);
//当move事件来的时候我们去计算本次的x值和上次的
//x值,得到一个差值
float yDiff = Math.abs(y-mLastY);
//y值的计算和x一样
if(xDiff > yDiff){
//x的差值大于y的差值,表示当前是左右滑动。此时应该把事件交给viewpager处理,拦截事件
isIntercept = true;
break;
}
if(yDiff > xDiff){
//y值大于x值,表示当前是上下滑动,此时应该把事件交给listview处理,不拦截事件
isIntercept = false;
break;
}
// break;
}
mLastX = x;//更新上一次的x值和y值
mLastY = y;
return isIntercept;
}
方法2:在子view中做滑动冲突处理,listview中的代码如下:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
//请求父view不拦截事件
break;
case MotionEvent.ACTION_MOVE:
float xDiff = Math.abs(x-mLastX);
float yDiff = Math.abs(y-mLastY);
if(xDiff > yDiff){
//当前是左右滑动,自己不需要处理事件,请求父view拦截事件。
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
default:break;
}
mLastX = x;
mLastY = y;
//调用父类的dispatchTouchEvent处理事件
return super.dispatchTouchEvent(ev);
}
viewPager中的代码如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//在子view中进行冲突处理.
if(ev.getAction() == MotionEvent.ACTION_DOWN){
super.onInterceptTouchEvent(ev);
//必须返回false,否则子view无法收到事件,此处会有一个面试题
return false;
}
//返回true,是为了当子view请求父view拦截事件的时候,好拦截事件
return true;
}
在子view中处理冲突和在父view中处理冲突的原理差不多,都是通过拦截和不拦截的方式将事件分给需要的view。回答的时候就把两种方法大致描述一下。
然后接着,面试官可能会问你:为啥不能拦截down事件,拦截了down事件,后面的move,up事件还能收到吗?
这两个问题其实互为因果,也就是拦截了down事件,后面的move,up事件都无法收到了。这时候你就可以开始将你看的事件分发机制的源码摆出来了:
...省略了部分代码
// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
//如果子view没有调用requestDisallowInterceptTouchEvent方法设置标志的话,这个地方会为false,因为在前面down事件来的时候会重置一下标志
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);//若是拦截了down事件,这个地方会返回true;无法进入到接下来的事件分发逻辑,然后mFirstTouchTarget就不会被赋值,无法走入到当前的代码逻辑中,导致后面来的move和up事件直接会被拦截
=============插播片段==============
if (!canceled && !intercepted) {
....
// 事件分发处理逻辑
.....
}
===========================
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
//如果没有处理down事件的时候,move和up事件都会被拦截
intercepted = true;
}
...省略了部分代码
具体的事件分发流程,可以看我上一篇博客根据热门面试题分析Android事件分发机制(一)
(四)总结:
其实事件分发机制和滑动冲突只要理解了源码都不难解决,我的建议就是要看博客然后自己去撸源码,写demo模拟每一种场景,这时你就会发现这些原理都是通的,在面试的时候也能帮你拿到主动权,大多数时候我们面试的时候感觉自己都被面试官气势给压住,其实都是我们技术了解得不深的原因。当我们技术了解得够透彻的时候,你去面试的时候会发现,面试官会被你虐的。那种感觉特别爽
(五)demo地址
这个源码我是放到gitee上的,已经申请了开放权限,还在审批,如果急须源码的伙伴,可以留个邮箱,我私发给你们~~~~
事件冲突演示demo地址
边栏推荐
- How to solve the problem of golang select mechanism and timeout
- Mysql database index study notes
- Pycharm importing third-party libraries
- 【BW16 应用篇】安信可BW16模组/开发板AT指令实现MQTT通讯
- 第一讲:鸡蛋的硬度
- stm32和电机开发(从单机版到网络化)
- Mysql:select ... for update
- Kubernetes cluster capacity expansion to add node nodes
- Netease cloud wechat applet
- Using JWT to realize login function
猜你喜欢
Unity shader (learn more about vertex fragment shaders)
Sublime Text4 download the view in bower and set the shortcut key
二叉树高频题型
【frida实战】“一行”代码教你获取WeGame平台中所有的lua脚本
超十万字_超详细SSM整合实践_手动实现权限管理
细说Mysql MVCC多版本控制
Mysql:select ... for update
Mysql database lock learning notes
信息安全实验一:DES加密算法的实现
华为HCIP-DATACOM-Core_03day
随机推荐
CMD startup software passes in parameters with spaces
面试被问到了解哪些开发模型?看这一篇就够了
IIS faked death this morning, various troubleshooting, has been solved
如何成为一名高级数字 IC 设计工程师(1-6)Verilog 编码语法篇:经典数字 IC 设计
VSCode+mingw64
Nested (multi-level) childrn routes, query parameters, named routes, replace attribute, props configuration of routes, params parameters of routes
Unittest simple project
12、 Sort
PLC信号处理系列之开关量信号防抖FB
Pycharm importing third-party libraries
Binary tree high frequency question type
Information Security Experiment 3: the use of PGP email encryption software
In fact, it's very simple. It teaches you to easily realize the cool data visualization big screen
[4G/5G/6G专题基础-147]: 6G总体愿景与潜在关键技术白皮书解读-2-6G发展的宏观驱动力
Jenkins+ant+jmeter use
VSCode+mingw64+cmake
JS逆向教程第一发
十二、排序
csdn涨薪技术-浅学Jmeter的几个常用的逻辑控制器使用
NATAPP内网穿透