9)touch事件的传递
touch事件既是用手触摸屏幕所触发的事件。这些事件基本包括按下Down,移动Move
取消Cancel和离开触摸屏Up四种事件。一个完整的Touch过程一般是由Down->(Move)
->Up/Cancel这四个事件做成,值得注意的是,一个完整的触摸事件必须由Down开始,
再到Up/Cancel技术,中间的Move可有可无,当然touch事件不止这四个事件,但是这
四个事件是最基本,开发中必须考虑到的。
当用户开启应用触摸屏幕,系统服务就通过IPC通知应用的主线程Lopper,最终传递到我
们应用中的Activity,View和ViewGroup中。
一个touch事件要传递到View中,必须经过Activity向下分发,如果在ViewGroup在子View
中找到可以处理这个事件的View,则向下传递下去,否则ViewGroup会尝试处理这个事件。
(1)View的Touch逻辑
分发:dispatchTouchEvent向接收Touch事件的子View(包括自己)派发事件,对于
View而非ViewGroup来说,只会对自己分发
处理:OnTouchListener在dispatchTouchEvent中被调用,是可选方法。onTouchEvent
默认方法,在dispatchTouchEvent中被调用,如果设置了OnTouchListener,并且
OnTouchListener消费了这个事件,返回true,则不会触发这个函数。
(2)dispatchTouchEvent
- 派发事件时首先停止嵌套滑动(5.0以后)
- 如果View开启了安全检测(setFilterTouchesWhenObscured(true))并且当前View所在
的Window被其他Window整改的话,则不会调用在处理Touch事件。
- 如果当前View是Enabled,才会调用OnTouchListener
- 不管Enable与否,只要OnTouchListener没有处理事件就会调用onTouchEvent()来处理事件
(3)onTouchEvent
- 不管View是否是Enabled,只要是clickable或者longclickable,就一定消费事件(返回true)
- 如果View是UnEnabled,并且clickable或者longclickable,就只会消费事件不做其他操作
- 如果View是Enabled,先看看TouchDelegate消费与否,如果不消费再给自己消费
- 处理包括focus,press,click,longclick事件
(4)常见的Touch事件处理问题解决
- touch监听器没被调用到?
看View.dispatchTouchEvent(),ViewGroup.dispatchTouchEvent()
a)如果是View非使能,直接用setEnabled(true)
b)如果是事件被这个View的viewparent拦截了。可以修改这个viewparent的onInterceptTouchTouchEvent(),
或者在这个View中调用getParent().requestDisallowInterceptTouchEvent()
- 双层滑动模块嵌套后发生滑动不了的现象?
看ViewGroup.dispatchTouchEvent() 如果是事件被这个View的viewparent拦截了。可以修改这个viewparent
的onInterceptTouchTouchEvent(),或者在这个View中调用getParent().requestDisallowInterceptTouchEvent()
- 设置了onClickListener后,点击View没有反应?
看View.onTouchEvent()
a)如果是View非使能,直接用setEnabled(true)
b)可能覆盖了onTouchEvent(),需要在覆盖的方法调用super.onTouchEvent()或者手动调用performClick()
- 点击两下View才调用onClickListener的bug?
看View.onTouchEvent() 这个其实是安卓的设计,当某个View调用了setFocusableInTouchMode(true)后,
第一次点击会引起这个View的focus,第二次点击才会调用onClickListener,只需要设置
setFocusableInTouchMode(false)即可。问题解决