自定义View的触摸反馈
重写onTouchEvent(),在方法内部定制触摸反馈算法
是否取消事件取决于ACTION_DOWN事件或PONITER_DOWN事件是否返回true
MotionEvent
getActionMasked()和getAction()
POINTER_DOWN / POINTER_UP 和 getActionIndex()
onTouchEvent()
当用户按下(ACTION_DOWN)
如果不在滑动控件中,切换至按下状态,并注册长按计时器
如果在滑动控件中,切换至按下状态,并注册按下计时器
当进入按下状态并移动(ACTION_MOVE)
重绘Ripple Effect
如果移动出自己的范围,自我标记本次事件失效,忽略后续事件
当用户抬起(ACTION_UP)
如果是按下状态并且未触发长按,切换至抬起状态并触发点击事件,并清除一切状态
如果已经触发长按,切换至抬起状态并清除一切状态
当事件意外结束(ACTION_CANCEL)
切换至抬起状态,并清除一切状态
自定义ViewGroup 的触摸反馈
除了重写onTouchEvent(),还需要重写onInterceptEvent()
onInterceptEvent() 不用在第一时间返回true,而是在任意事件,需要拦截的时候返回true就行
触摸反馈的流程
Activity.dispatchEvent()
递归:ViewGroup(View).dispatchTouchEvent()
ViewGroup.onInterceptTouchEvent()
ViewGroup.onIntercepTouchEvent()
Child.dispatchTouchEvent()
Super.dispatchEvent()
View.onTouchEvent()
Activity.onTouchEvent()
View.dispatchTouchEvent()
如果设置了OnTouchListener,调用OnTouchListener.onTouch()
如果OnTouchListener消费了事件,返回true
如果onTouchListener没有了消费事件,继续调用自己的onTouchEvent(),并返回和onTouchEvent()相同的结果
如果没有设置onTouchEvent,同上
ViewGroup.dispatchEvent()
如果是用户初次按下(ACTION_DOWN),清空TouchTargets和DISALLOW_INTERCEPT标记
拦截处理
如果不拦截并且不是CANCEL事件,并且是DOWN或者POINTER_DOWN,尝试把pointer(手指)通过TouchTarget分配给子View;并且如果分配给了新的子View,调用child.dispathTouchEvent()把事件传递给子View
看有没有TouchTarget
如果没有TouchTarget,调用自己的super.dispatchTouchEvent()
如果有,调用child.dispatchEvent()把事件传给对应的子View(如果有的话)
如果是POINTER_UP,从TouchTargets中清除POINTER信息,如果是UP或CANCEL,重置状态
TouchTarget
作用:记录每个子View是被哪些pointer(手指)按下的
结构:单向链表
拦截处理
如果不是初次按下,并且没有TouchTarget,直接拦截
如果不是初次按下,或者有TouchTarget
如果设置了disallow intercept,不拦截
否则,调用onInterceptTouchEvent(),如果返回true则拦截,返回false则不拦截
网友评论