Android - 触摸事件分发机制
1、本文是对教程视频 「Mastering the Android Touch System」以及 PPT 的摘抄,中文字幕视频来源于优酷。
示例代码(custom-touch-examples-master.zip)下载地址:https://github.com/devunwired
一、基础知识
1、所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间以及几个手指(多指触摸)等
2、事件类型分为ACTION_DOWN,ACTION_UP,ACTION_MOVE,ACTION_POINTER_DOWN,ACTION_POINTER_UP,ACTION_POINTER_CANCEL,每个事件都是以ACTION_DOWN开始以ACTION_UP结束
3、事件处理分为三类:传递-dispatchTouchEvent(), 拦截-onInterceptTouchEvent(), 消费-onTouchEvent()以及onTouchListener
二、传递流程
1、事件从Activity.dispatchTouchEvent()开始传递,只要没有被拦截, 从最上层的View(ViewGroup)开始往下(子View)传递, 子View可以通过onTouchEvent()对事件进行处理
2、事件由父View(ViewGroup)传递给子View, ViewGroup可以通过onInterceptTouchEvent()对事件进行拦截, 停止事件向下传递;
3、如果事件从上往下传递过程中没有被停止, 并且最底层子View没有消费事件, 事件将会反向往上传递, 此时父View(ViewGroup)可以进行消费,如果事件还是没有被消费, 最后会到Activity的onTouchEvent();
4、如果View没有对ACTION_DOWN进行消费, 后续的其他事件不会传递;
5、onTouchListener 优先于 onTouchEvent() 对事件进行消费, 以上消费表示相应函数返回值为true ;
每个用户触摸事件被封装为MotionEvent
用户手势动作有以下类型:
ACTION_DOWN
ACTION_MOVE
ACTION_UP
ACTION_POINTER_DOWN
ACTION_POINTER_UP
ACTION_CANCEL
MotionEvent包含以下信息:
位置
触摸手指个数
时间
历史(系统会对MotionEvent进行批处理,比如,发生5次事件只使用第五次数据)
事件由Activity-dispatchTouchEvent()开始传递
由上往下传递
ViewGroup分发事件给子View
事件可以被拦截
View如果对事件感兴趣必须消费ACTION_DOWN
任何未被消费的事件最终由Activity-onTouchEvent()处理
View/ViewGroup的 onTouchListener 可以拦截事件
优酷视频:「https://newcircle.com/s/post/1663/tutorial_enhancing_android_ui_with_custom_views_dave_smith_video」
对Android的触摸机制做一个全面的探索,让你掌握在应用中触摸事件如何被分发以及Android如何对事件进行处理
每一个由设备上的触摸屏产生的事件都被包裹成MontionEvent
Android只定义了一种手势(gesture),此手势的全部事件组成发生在Action_down与Action_up之间(即:每个手势以事件ACTION_DOWN开始以事件ACTION_UP结束)
那么事件到底是如何在你的应用中传递了?
对于每一个硬件或底层框架产生的事件,这些事件最先被发送到Activity的dispatchTouchEvent()
这些事件将开启其旅程,由Activity开始往下传递给你的视图结构树
传递机制:
事件会在你的程序中从上往下再从下往上穿梭直到某个View宣布对这个事件感兴趣
每个View/ViewGroup都会有onTouchEvent函数,其返回true表示对事件感兴趣,此时系统将中断事件传递链
dispatch一层一层往下调用,onTouchEvent一步一步往上返回
onTouchListener与onTouchEvent一致
拦截事件:
ViewGroup可以通过onInterceptTouchEvent()[返回true]对事件进行中断或者窃取
停止事件分发转而自己处理事件(例如, ScrollView中有Button, ScrollView滚动时, ScrollView优先Button响应事件)
当onInterceptTouchEvent返回true时,改变的仅仅是ViewGroup直接把关于此手势当前事件以及后续事件直接发送给ViewGroup自身的onTouchEvent()而不是把事件分发给子View
[注] 此时子View会接收到Action_Cancel, 系统为了让子View知道它已经不能再接收到该手势的任何事件了, 因此, 一般Action_cancel与Action_up是放在一起处理的
子View可以由requestDisallowTouchIntercept(true)剥夺ViewGroup对那个手势的中断能力
[注] 该标示只对当前手势有效,新手势开始时,该标示将被清空
如果视图层级中没有视图去消费Action_down,后续的事件不会在视图层级中进行传递,直接由Activity-dispatchTouchEvent()到Activity-onTouchEvent
如果事件被某个视图消费,它们就不会返回给上一层了
框架里面已经为我们内建了很多触摸处理器,例如:onClickListener,onLongClickListener
对于复杂的触摸交互,可以使用GestureDetector, 这些手势监听器可以监测到像滚动或者飞划(fling)等这些常见手势
ScaleGestureDetector:缩放手势监听器(监听器作为一种数学计算引擎)
用法:需要在onTouchEvent或者onTouchListener中将事件提取出来并送到监听器,
监听事件跟事件处理之间没有直接的联系;
浙公网安备 33010602011771号