[UI]抽屉菜单DrawerLayout分析(二)
继续分析DrawerLayout的手势分发部分
谈到手势分发,这本身就是个好话题,DrawerLayout作为继承自ViewGroup得布局他可以拦截手势也可以分发给子view,也就是在onInterceptTouchEvent中做的操作,但是他的下面还有一个onTouchEvent方法,先看哪个呢?追溯代码我们可以知道ViewGroup继承自View,而onTouchEvent是View的方法
我们还是先花点时间把两者的关系先确认再继续。
onInterceptTouchEvent和onTouchEvent---鸡和蛋?
定位到ViewGroup,可以发现onInterceptTouchEvent分定义如下,从它前面一段非常长的注释就可以看出其重要性和复杂,默认的返回是false
/**
* Implement this method to intercept all touch screen motion events. This
* allows you to watch events as they are dispatched to your children, and
* take ownership of the current gesture at any point.
*
* <p>Using this function takes some care, as it has a fairly complicated
* interaction with {@link View#onTouchEvent(MotionEvent)
* View.onTouchEvent(MotionEvent)}, and using it requires implementing
* that method as well as this one in the correct way. Events will be
* received in the following order:
*
* <ol>
* <li> You will receive the down event here.
* <li> The down event will be handled either by a child of this view
* group, or given to your own onTouchEvent() method to handle; this means
* you should implement onTouchEvent() to return true, so you will
* continue to see the rest of the gesture (instead of looking for
* a parent view to handle it). Also, by returning true from
* onTouchEvent(), you will not receive any following
* events in onInterceptTouchEvent() and all touch processing must
* happen in onTouchEvent() like normal.
* <li> For as long as you return false from this function, each following
* event (up to and including the final up) will be delivered first here
* and then to the target's onTouchEvent().
* <li> If you return true from here, you will not receive any
* following events: the target view will receive the same event but
* with the action {@link MotionEvent#ACTION_CANCEL}, and all further
* events will be delivered to your onTouchEvent() method and no longer
* appear here.
* </ol>
*
* @param ev The motion event being dispatched down the hierarchy.
* @return Return true to steal motion events from the children and have
* them dispatched to this ViewGroup through onTouchEvent().
* The current target will receive an ACTION_CANCEL event, and no further
* messages will be delivered here.
*/
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
前两段告诉我们,复写onInterceptTouchEvent方法,可以实现监听所有的动作事件MotionEvent,在向子view传递事件前做我们需要的操作,当然这指的是和这个viewgroup相关的事件;同时我们需要慎重处理该函数,因为他和onTouchEvent关系非常紧密,下面是事件接收的顺序:
首先接收的的事按下事件,down事件,他可以被view处理也可以在自身的onTouchEvent里处理,所以实现onTouchEvent并且返回true,这样onTouchEvent继续才能收到down之后的其他事件,同时onInterceptTouchEvent不会在收到后续事件,因为已经转移到onTouchEvent处理了。
那么什么时候onInterceptTouchEvent会把后续事件转移到他的onTouchEvent呢?这取决于onInterceptTouchEvent的返回值,如果返回false,所有事件都会先分发到这里,然后再到目标view的onTouchEvent;相反如果返回true,那么onInterceptTouchEvent将不再收到后续事件,并且目标view会收到cancel事件,接着自身的onTouchEvent几首后续的事件。
这其实从名字来看是比较好理解的onInterceptTouchEvent表示在截取触摸事件的被调用的方法,既然是截取就可以直接吧事件截下来后不再往后传递,这是就是上面的第二种情况,返回true,即我们自己消耗了触摸事件,子view将没有机会得到唤醒。
大致意思就是如果希望自身消耗掉改事件就可以直接返回true,这一点和onTouchEvent的返回类似目的。
博客园有篇文章对这些事件分发做了很好的分析:http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html
详细的阐述了了dispatchTouchEvent,onInterceptTouchEvent以及onTouchEvent之间的关系
现在我们回过头来看DrawerLayout里的分发是如何写的:
重写了后面两个方法,先看onInterceptTouchEvent:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
// "|" used deliberately here; both methods should be invoked.
final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev) |
mRightDragger.shouldInterceptTouchEvent(ev);
boolean interceptForTap = false;
switch (action) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mInitialMotionX = x;
mInitialMotionY = y;
if (mScrimOpacity > 0 &&
isContentView(mLeftDragger.findTopChildUnder((int) x, (int) y))) {
interceptForTap = true;
}
mDisallowInterceptRequested = false;
mChildrenCanceledTouch = false;
break;
}
case MotionEvent.ACTION_MOVE: {
// If we cross the touch slop, don't perform the delayed peek for an edge touch.
if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
mLeftCallback.removeCallbacks();
mRightCallback.removeCallbacks();
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
closeDrawers(true);
mDisallowInterceptRequested = false;
mChildrenCanceledTouch = false;
}
}
return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
}
1.首先从touch event里面获取当前具体的action动作,MotionEventCompat.getActionMasked(ev),内部实际上做了一次按位于操作event.getAction() & ACTION_MASK;
2.检查当前是否满足截取drag状态,用于决定onInterceptTouchEvent返回值,这里有个注解说是故意用了|或,而不是||或,两者区别在于||只要第一个条件满足就不在执行第二个检查,二|不同,无论如何都会将两个条件检查一遍;
3.接下来是几个case,根据当前的action做处理;
ACTION_DOWN,当按下时记录按下点的x,y坐标值,根据条件设置当前是否满足tap状态,具体条件有两个,一是mScrimOpacity,表示子view中在屏幕上占据的最大宽度(0-1),二时根据坐标点的位置取得改点对应的最上层view对象,如果是预定义的content view即DrawerLayout里的主内容展示view,也就是同时满足view在屏幕上且点击的位置直接落在了content view上。
ACTION_MOVE,当手按下后开始在屏幕上移动时,如果垂直和水平上的位移差量达到了drag helper的阀值则一处左右两边的回调接口
ACTION_CANCLE和ACTION_UP,手势结束后,关闭菜单
最后结合几个状态来那个来决定onInterceptTouchEvent返回true还是false,
未完待续
转载于:https://www.cnblogs.com/avenwu/p/3675838.html
[UI]抽屉菜单DrawerLayout分析(二)相关推荐
- [UI]抽屉菜单DrawerLayout分析(三)
在[UI]抽屉菜单DrawerLayout分析(一)和[UI]抽屉菜单DrawerLayout分析(二)中分别介绍了DrawerLayout得基本框架结构和ViewDragerHelper的作用以及手 ...
- Toolbar与抽屉菜单DrawerLayout
(一)toolbar用来替代Actionbar,也就是标题栏. 首先打开res/values/styles.xml 将AppTheme的主题的parent主题改为 Theme.AppCompat.Li ...
- android 2个界面抽屉,Android使用DrawerLayout创建左右两个抽屉菜单
在Android support.v4 中有一个抽屉视图控件DrawerLayout.使用这个控件,可以生成通过在屏幕上水平滑动打开或者关闭菜单,能给用户一个不错的体验效果. 最近在项目中,设计中有用 ...
- android 抽屉组件,Android组件之DrawerLayout实现抽屉菜单
DrawerLayout组件同样是V4包中的组件,也是直接继承于ViewGroup类,所以这个类也是一个容器类. 抽屉菜单的摆放和布局通过android:layout_gravity属性来控制,可选值 ...
- BetaFlight模块设计之二十:CMS菜单模块分析
BetaFlight模块设计之二十:CMS菜单模块分析 CMS菜单模块 CMS菜单按键控制 CMS菜单Elements CMS_Menu OSD_Etnry Element类型 可调Element类型 ...
- Android UI开发第三十二篇——Creating a Navigation Drawer
Navigation Drawer是从屏幕的左侧滑出,显示应用导航的视图.官方是这样定义的: The navigation drawer is a panel that displays the ap ...
- 如何使用React Native构建嵌套的抽屉菜单
by Dhruvdutt Jadhav 由Dhruvdutt Jadhav 如何使用React Native构建嵌套的抽屉菜单 (How to build a nested drawer menu w ...
- mysql抽屉图标_React Native自定义组件实现抽屉菜单控件效果
一.需求分析 原生开发中,自定义View可谓是屡见不鲜的事情,往往系统的控件总不能满足现实的需求.五花八门的产品设计需要我们做出不同的View.关于自定义View的内容网上已经有很多的博文,本篇博客要 ...
- Flutter Drawer 抽屉菜单示例
一.Flutter Drawer组件简介 1.源码查看 const Drawer({Key? key,this.elevation = 16.0, //阴影效果大小this.child, //内容元素 ...
最新文章
- stl clocklist 查找元素_C++算法竞赛中常用的STL
- jekenis父子结构项目打包_maven 父子工程打包 并且上传linux服务器
- PostgreSQL 8.4.3 Final / 9.0 Alpha 4
- 互联网大厂“抢填”高考志愿
- zend studio设置自动保存
- 入侵微博服务器刷流量,开发者获刑 5 年;马化腾重回中国首富;支持 M1 芯片,VS Code 1.54 发布 | 极客头条...
- HashMap遍历方式
- 0.42-0.5+0.08与0.08-0.5+0.42是不完全相等,Why is 0.3 - 0.2 - 0.1 (or similar) not equal to zero?
- android定位欺骗,1020. Android GPS定位欺骗(模拟定位)的3类途径4种方式
- 用VBS脚本实现软件定条件开启
- 计算机快捷键大全列表6,快捷键大全excel
- Shell习题100例(2)
- 栈的应用:火车调度问题
- H5 授权微信第三方登录
- 一篇文章讲清什么是NVMe
- 重庆大学计算机学院课题组,【计算机】计算机学院关于智能计算的大规模优化学术报告圆满结束...
- 从零开始搭建本地mongodb环境
- 2022年中国前10大互联网公司广告营收榜
- 关于IDFA、CAID和「5. 1.2 - Data use sharing」
- 人工智能AI 计算平台介绍
热门文章
- linux 下 将 shell script 与 一个桌面图标联系在一起 (2)
- 6.10 docker (二) 守护态运行
- 我为 VS Code 开发了一个 Deno 插件
- F5配置irule,使其系统在X个时间段提供服务,其余时间显示维护页面
- eclipse下运行自定义maven命令
- 初学算法-快速排序与线性时间选择(Deterministic Selection)的C++实现
- WIN7下黑苹果懒人版硬盘安装not a HFS partition注意问题
- 10年磨一剑,软件编程走火入魔之:把简单的功能做个彻彻底底、把劳动成果重复利用...
- 我要一颗原子弹 -- 开发者思维
- RecyclerView 缓存机制