说一下安卓的touch事件分发机制

先从事件的传递开始.

一个事件到达界面时, 它的入口是dispatchTouchEvent. 这个方法是视图处理事件的惟一接口, 全部到达视图的事件, 都必须通过这个方法.

简单地说, 系统接收到一个事件, 要丢到一个LinearLayout里面, 怎么办?
直接调这个dispatchTouchEvent, 接收返回的true或者false, 完了.后面的处理就和这个LinearLayout不要紧了.

那就有人问了, 那onInterceptTouchEvent, onTouchEvent, onClickListenr, 或者这个LinearLayout里面的Button, 不是还没处理吗, 怎么就完了?

虽然外部只调用dispatchTouchEvent, 可是在这个方法内部, 它本身会根据一系列逻辑调用这些方法.ide

件在视图之间传递的顺序大概是这样的:


父容器的dispatchTouchEvent-->调用内部容器的dispatchTouchEvent-->调用基本控件的dispatchTouchEvent.
这里的容器就是ViewGroup, 控件就是各类View.



经过这样的传递, 一个复杂的组件对它的上层来讲就变得统一了: 我不要去关心你里面有什么乱七八糟的基本控件, 怎么摆放, 怎么处理. 我分分钟几十万上下, 找一个小小的具体的Button我累不累? 反正我就把事件丢给你, 怎么处理你来决定.
一样他的下级也是这个思路, 把事件丢到更下一级, 最终传达到一个Button让它响应处理.


这就是责任链模式.
可是这样又产生一个问题: 若是父容器只能起一个传递的做用, 事件只能由子控件响应, 那我ScrollView怎么滑动? ViewPager怎么切换? 工做不能都压给最底层的员工吧, 总有些事情是我经理得本身干的吧, 好比作报表写工做计划泡前台调戏测试之类的..... 咳咳扯远了.


因此这里就须要有一个判断的方法. 一个事件来了, 我本身审核一下, 这个是个人职责, 那后续的事情我就揽下来, 不往下传了. 不然就继续往下传. 嘿嘿我真是太机智了.


这个判断的方法就是onInterceptTouchEvent.

 
说到这里, 要区分 "动做" 和 "事件" 的概念了.


动做就是用户的一个完整的操做, 好比一个点击, 一个滑动, 等等.
而事件就是MotionEvent了.
咱们知道全部的事件MotionEvent其实都是瞬态的, 一个事件自己只表明这一瞬间是什么样子. 你没法从单个MotionEvent看出用户当前是滑动仍是长按, 滑动了多远, 向左仍是向右. 一个完整的滑动动做是由不断触发 ACTION_DOWN, ACTION_MOVE x N, ACTION_UP(或者CANCEL)来组成的. 这些ACTION_DOWN, ACTION_MOVE表明事件的类型(getAction()).


那么问题又来了.一个单独的瞬态的ACTION_MOVE, 我怎么知道这个事件是2秒前的那次DOWN仍是5秒前的那次DOWN带着的? 我如何判断一个完整的动做处理完没有?


视图是经过getDownTime() 这个属性. 每一个动做的一系列事件都有相同的downTime, 也就是DOWN事件的getEventTime这个方法所返回的时间. 


因此, 一个完整的动做是由一组MotionEvent组成的, 他们拥有共同的downTime. 当视图接收到具备一个新的downTime的事件时, 它就认为, 以前的动做已经处理完毕了.


这一块基本不多有提到过, 平时也用不太上. 可是很重要.
 
 
这个方法的参数虽然是一个事件, 但它实际上拦截的是一个完整的动做. 这就意味着, 若是你在DOWN事件或者某一个MOVE事件返回了true(意味着告诉视图:"我要拦截了, 这个动做我来处理!"), 那以后的全部事件都不会再继续往子视图传递了,直到有一个新的动做开始! 到这里, 咱们能够试图解释一下, 为何当ViewPager放在ScrollView里面时, 左右滑动常常变得很困难的缘由.(筒子们能够试着本身动手写一个Demo, 你会发现左右滑动切换会变得比在外面困难不少.) 缘由就是ScrollView在接收到MOVE事件时, 会判断先后两次事件的y坐标之差, 超过必定阈值就会认为是上下滑动事件, 而后就无情地经过onInterceptTouchEvent接管掉了. 并且这个阈值特别小...... 而咱们在左右滑动的时候, 手指很难保证彻底水平地动做. 稍微有一点角度就产生了Y值的变化, 而后ScrollView大爷的onInterceptTouchEvent就以为"卧槽这是上下滑动事件啊劳资不能无论啊!!!!".而后果断返回true. 因而可怜的ViewPager再也没接收到后续的事件, 也就切换不了了.
相关文章
相关标签/搜索