继续分析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,

未完待续

作者:小文字
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

[UI]抽屉菜单DrawerLayout分析(二)的更多相关文章

  1. [UI]抽屉菜单DrawerLayout分析(一)

    本文转载于:http://www.cnblogs.com/avenwu/archive/2014/04/16/3669367.html 侧拉菜单作为常见的导航交互控件,最开始在没有没有android官 ...

  2. [UI]抽屉菜单DrawerLayout分析(三)

    在[UI]抽屉菜单DrawerLayout分析(一)和[UI]抽屉菜单DrawerLayout分析(二)中分别介绍了DrawerLayout得基本框架结构和ViewDragerHelper的作用以及手 ...

  3. Android抽屉菜单DrawerLayout的实现案例

    (1)项目布局文件 activity_main.xml <android.support.v4.widget.DrawerLayout xmlns:android="http://sc ...

  4. android 5.X Toolbar+DrawerLayout实现抽屉菜单

    前言  android5.X新增的一个控件Toolbar,这个控件比ActionBar更加自由,可控,因为曾经的ActionBar的灵活性比較差,所以google逐渐使用Toolbar替代Action ...

  5. Android UI开发第三十二篇——Creating a Navigation Drawer

    Navigation Drawer是从屏幕的左侧滑出,显示应用导航的视图.官方是这样定义的: The navigation drawer is a panel that displays the ap ...

  6. iOS开发-UI 从入门到精通(二)

    iOS开发-UI 从入门到精通(二)是对 iOS开发-UI 从入门到精通(一)知识点的巩固,主要以习题练习为主,增强实战经验,为以后做开发打下坚实的基础! ※开发环境和注意事项: 1.前期iOS-UI ...

  7. 可折叠的ToolBar+抽屉菜单NavigationView+浮动按钮FloatButton

    使用Material Design风格的ToolBar和抽屉导航 先看个简单的运行效果 主要记录下布局的写法 1 用到的Google Design依赖和V7包依赖 compile 'com.andro ...

  8. AndroidUI 侧滑菜单 DrawerLayout的使用

    直接上代码: activity_main.xml: <android.support.v4.widget.DrawerLayout xmlns:android="http://sche ...

  9. wemall doraemon中Android app商城系统解决左侧抽屉菜单和viewpager不能兼容问题

    完美解决左侧抽屉菜单和viewpager不能兼容左右滑动的问题,可进行参考. WeMall-Client/res/layout/wemall_main_ui.xml </RadioGroup&g ...

随机推荐

  1. spark aggregate

    该函数官方的api,说的不是很明白: aggregate(zeroValue, seqOp, combOp) Aggregate the elements of each partition, and ...

  2. poj 1065 Wooden Sticks_贪心

    题意:将木棍放在机器里处理,第一根需要一分钟,剩余的如果大于等于前边放入的长度和重量,就不用费时间,否则需要一分钟,计算给出一组数的最少时间. 思路:先按长度排序,相同在比较重量,然后按顺序比较得出结 ...

  3. CoreData多表操作.

    这次给大家带来的是CoreData多表操作的使用. 首先我们要对CoreData来进行多表操作我们先要创建至少两个实体在工程中. 在创建完成这两个对应的工程实体文件和工程中的类文件后我们现在需要创建一 ...

  4. 【JSON异常系列】new JSONObject对象时卡死原因

    8:47 2015/7/11 昨天晚上在使用JSON时,在创建JSONObject对象的时候不报错也不抛出异常.但就是new 不出来JSONObject的对象,这是一个非常奇葩的现象. 最后才发现原来 ...

  5. [置顶] ANT build.xml文件详解

    Ant的优点 跨平台性.Ant是用Java语言编写的,所示具有很好的跨平台性. 操作简单.Ant是由一个内置任务和可选任务组成的. Ant运行时需要一个XML文件(构建文件). Ant通过调用targ ...

  6. 【最小费用最大流】【HDU1533】【Going Home】

    题意 给你一个类似这样的图 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 问所有H移动到所有m上花费最少的步数 以所有H ...

  7. How to recover a skipped tablespace after an incomplete recovery with resetlogs? [ID 1561645.1]

    n this Document   Goal   Solution This document is being delivered to you via Oracle Support's Rapid ...

  8. iOS设计模式解析(四)组合模式

    组合模式:将对象组合成树形结构以表示"部分-整体"的层次结构.组合是的用户对单个对象和组合对象的使用具有一致 Cocoa Touch中组合模式使用:Cocoa Touch框架中,U ...

  9. <转>Java的一些历史

      Java是一种固执己见的语言,它具有很好的可读性,初级程序员很容易上手,具有长期稳定性和可支持性.但这些设计决定也付出了一定的代价:冗长的代码,类型系统与其它语言相比显得缺乏弹性. 然而,Java ...

  10. EventBus通信

    需求: 1.ActivityA打开ActivityB 2.在B中执行某操作后,同时执行A中的方法 lib下载:eventbus-2.4.0.jar  jmmy 1.在EventBusTestActiv ...