Androi事件分发( 二),解决事件冲突
通过《Android事件分发(一)》我们了解了Android的事件分发机制,不熟悉的,可以回头再去看一遍。
有了这方面的知识基础,我们来解决实际研发的过程中,老生常谈的事件冲突问题。
解决这类问题,其实是有方法的。下面先介绍这两种方法,然后再结合以上三种问题,分别进行讲解
方法一:外部拦截法
顾名思义,外部拦截法,就是指在外部进行拦截,让事件不传递下去。其实就是对外部的dispatchTouchEvent和onInterceptTouchEvent动手脚
方法二:内部拦截法
事件冲突大致分为三种
1.方向一致
我们用ScrollView嵌套ListView,同为上下方向的滑动。
我们假设一个需求:
1.listView向下滑时,如果还没有滑到listView的头部的话,listView继续滑动;否则ScrollView滑动。
2.listView向上滑时,如果还没有滑到listView的底部的话,listView继续滑动;否则ScrollView滑动。
<com.example.weights.CustomScrollViewandroid:id="@+id/scrollView"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="100dp"android:background="#0000ff"android:text="头部" /><ListViewandroid:id="@+id/list_view"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#0000ff"app:adapter="@{da}" /><TextViewandroid:layout_width="match_parent"android:layout_height="100dp"android:background="#0000ff"android:text="尾部" />
1.1 外部拦截法
重写ScrollView的onInterceptTouchEvent
int tempY;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {boolean intercept = false;//表示是否拦截int y = (int) ev.getY();switch (ev.getAction()){case MotionEvent.ACTION_DOWN:tempY = y;//记录按下时的Y坐标intercept = super.onInterceptTouchEvent(ev);//这里返回的是false。不然,不会调用其他Action方法break;case MotionEvent.ACTION_MOVE:if(null != listView){if(listView.getFirstVisiblePosition() == 0 && y > tempY){//list显示第一个,而且是向下滑intercept = true;//ScrollView拦截break;}else if(listView.getLastVisiblePosition() == listView.getCount() - 1 && y < nowY){//list显示最后一个,而且是向上滑intercept = true;break;}intercept = false;}break;case MotionEvent.ACTION_UP:intercept = false;break;default:break;}return intercept;
}
所谓外部拦截法,其实就是外部父容器做处理。在这里,当父容器ScrollView拦截事件后,就会调用父容器ScrollView自己的onTouchEvent,即ScrollView处理滚动,否则交给ListView消费。
2.1 内部拦截法
int nowY;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {//内部拦截法int y = (int) ev.getY();switch (ev.getAction()){case MotionEvent.ACTION_DOWN:nowY = y;getParent().requestDisallowInterceptTouchEvent(true);//禁止父容器拦截事件break;case MotionEvent.ACTION_MOVE:View topView = getChildAt(0);View bottomView = getChildAt(getChildCount() - 1);if(y > nowY && getFirstVisiblePosition() == 0 && null != topView && topView.getTop() == 0){//往下滑,并且是第一项,父容器拦截getParent().requestDisallowInterceptTouchEvent(false);}else if(y < nowY && getLastVisiblePosition() == getCount() - 1 && null != bottomView && bottomView.getBottom() == getHeight()){//往上滑,并且是第后一项,父容器拦截getParent().requestDisallowInterceptTouchEvent(false);}break;}return super.dispatchTouchEvent(ev);
}
所谓内部拦截法,其实就是在内部子容器里,通过requestDisallowInterceptTouchEvent方法,控制父容器是否拦截事件。requestDisallowInterceptTouchEvent是ViewParent接口的一个抽象方法,实现是在ViewGroup里面
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {// We're already in this state, assume our ancestors are tooreturn;}if (disallowIntercept) {mGroupFlags |= FLAG_DISALLOW_INTERCEPT;//注意这里} else {mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;}// Pass it up to our parentif (mParent != null) {mParent.requestDisallowInterceptTouchEvent(disallowIntercept);}
}
注意mGroupFlags这个变量,回想下,在ViewGroup的dispatchTouchEvent方法里面有这么一段代码
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {//允许拦截intercepted = onInterceptTouchEvent(ev);ev.setAction(action); // restore action in case it was changed
} else {intercepted = false;
}
这里说明一点,在使用内部拦截法的时候,需要重写父容器的onInterceptTouchEvent,
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {if(ev.getAction() == MotionEvent.ACTION_DOWN){//这里需要返回false,因为如果这里返回true,事件就不会往下传递,导致子View无法接收事件return false;}else{//其他事件拦截。已配合子容器调用requestDisallowInterceptTouchEvent使用return true;}
}
这里的ScrollView没有重写,是因为ScrollView本身已经重写了onInterceptTouchEvent方法
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {...final int action = ev.getAction();if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {return true;}if (super.onInterceptTouchEvent(ev)) {return true;}
...return mIsBeingDragged;
}
2.方向不一致
典型的例子,就是ViewPager和ListView。不过,ViewPager已经做了处理,有兴趣的可以看看ViewPager的源码。
解决套路还是外部拦截和内部拦截,在判断条件上,需要做些调整。归根结底还是根据X和Y的滑动距离来判断是否消费事件。
3.多层嵌套,方向不一致
解决套路还是外部拦截和内部拦截,根据需要,把之拆开成以上两种情况,然后解决,这里就不多做介绍了,有兴趣的朋友,可以自行尝试。
胖子总结
- 自己写个demo,试一试,比看十遍文章都有用
- 温馨提示:点成线,线成面,切勿贪心,否则一脸懵逼
- 胖子有什么理解错误的,欢迎大家指出来,一起讨论、学习、进步
- 期待胖子为了巩固、加深基础的《Java虚拟机(JVM)》
Androi事件分发( 二),解决事件冲突相关推荐
- Android 系统(218)---Android的事件分发机制以及滑动冲突的解决
Android的事件分发机制以及滑动冲突的解决 声明: 本文主要涉及VIew的事件分发与滑动冲突的解决,关于View的事件分发流程的部分内容参考自: Android事件分发机制详解:史上最全面.最 ...
- 自定义View(二)--表层浅析View的事件分发机制和滑动冲突
转载请注明出处:From李诗雨:http://blog.csdn.net/cjm2484836553/article/details/54387722 不诗意的女程序猿不是好厨师~ 这篇文章来得有些曲 ...
- 【Android 事件分发】ItemTouchHelper 事件分发源码分析 ( 绑定 RecyclerView )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- 【Android View事件分发机制】滑动冲突
View内容滑动概念 scrollTo scrollBy scrollTo(x,y) x,y 是绝对值,如果x,y不变,重复调用是不会移动的. scrollBy(x,y) x,y是增量之,每次调用都会 ...
- Android View的事件分发机制和滑动冲突解决方案
这篇文章会先讲Android中View的事件分发机制,然后再介绍Android滑动冲突的形成原因并给出解决方案.因水平有限,讲的不会太过深入,只希望各位看了之后对事件分发机制的流程有个大概的概念,并且 ...
- View的Touch事件分发(二.源码分析)
Android中Touch事件的分发又分为View和ViewGroup的事件分发,先来看简单的View的touch事件分发. 主要分析View的dispatchTouchEvent()方法和onTou ...
- javaScript事件(二)事件处理程序
一.事件 二.事件流 以上内容见:javaScript事件(一)事件流 三.事件处理程序 前面提到,事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字.响应 ...
- button添加插槽之后绑定不来事件_javaScript基础事件(二)事件处理程序
前面提到,事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字.响应某个事件的函数就叫事件处理程序(也叫事件处理函数.事件句柄).事件处理程序的名字以&quo ...
- java 事件分发线程_事件分发线程EDT
所有的事件处理都在Event Dispatch Thread(EDT)上进行,此一类事件模型通常叫做单线程模型. 这种模型规定所有对组件的访问操作必须在EDT 上完成. 为什么对于组件的访问需要在ED ...
- java 事件分发线程_Java事件调度线程说明
我最近开始学习和探索Java中GUI编程的基础知识. 经过一段时间的编程,我只完成了后端工作或其他工作,因此,我最接近用户界面的是命令控制台(令人尴尬的是,我知道). 我正在使用Swing,据我所知, ...
最新文章
- AI+DevOps正当时
- Spartan-6系列内部模块介绍之可配置逻辑模块(CLB)
- 支持Windows 7的CAD—AutoCAD Civil 3D 2010
- boost::contract模块实现check宏的测试程序
- hibernate的映射关系配置及对会话工厂的初始化。以及struts2写实例查询
- wxpython实现简单图书管理系统
- 使用PostBackUrl属性实现跨页面传值
- redhat6.3下配置使用cenos yum源
- 发布一个域安全级别的无代码InfoPath表单作为文档库模版 (InfoPath 一)
- Windows 下修改 MySQL 编码为 utf8
- 1705. 吃苹果的最大数目
- ESXi配置vCenter服务器
- ai人工智能的数据服务_可解释的AI-它对数据科学家有何影响?
- Excel-VBA 快速上手(一、宏、VBA、过程、类型与变量、函数)
- iMac电脑启动ideal跑Java项目报错(Class JavaLaunchHelper is implemented in both...One of the two will be used.)
- 使用EditPlus 3时,如何重新设置HTML Page的Default模板
- Failed installing 'Tomcat9' service
- 速达3000pro saas数据库修复
- 图像宽度所占字节必须是4的倍数详解
- 特征值问题编程基础:特征值特征向量的求解和性质
热门文章
- 问题 H: A+B 输入输出练习VIII
- 阿里云飞天系统质效管理体系入选信通院“软件质效领航者”优秀案例
- PostgreSQL 磁盘空间的保护伞 PG_repack VS 表膨胀
- html都有哪些事件,HTML有哪些事件属性?
- 价值3888开源企业发卡网源码/全网对接/全新UI风格/完美运营
- python练习题:程序员问卷调查
- 条件概率下的全概率公式
- 双代号网络图如何用计算机画,怎么画双代号网络图,双代号网络图的绘制规则和步骤...
- python华表_鹤归华表 丁令威化鹤
- 原创分享 | 如何从非技术层面实现数据驱动