Android事件机制从小白到大神
2022-03-04 02:43:50 0 举报
Android事件机制史上最强分析,从案例,到原理,案例时序图和原理关键方法流程图全部放开,仔细阅读
作者其他创作
大纲/内容
View
activity dispatch false | touch true layout dispatch false | intercept false | touch false button dispatch false | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: onInterceptTouchEvent 0D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 0D/| view *: onTouchEvent 0D/| view *: onTouchEvent falseD/| view *: dispatchTouchEvent falseD/| layout *: onTouchEvent 0D/| layout *: onTouchEvent falseD/| layout *: dispatchTouchEvent falseD/|activity *: onTouchEvent 0D/|activity *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent 1D/|activity *: onTouchEvent 1D/|activity *: dispatchTouchEvent true
onTouchEventreturn false
onInterceptTouchEventreturn false
特例:viewgroup的dispatchTouchEvent方法中不进行调用super.dispatchTouchEvent,直接返回false activity dispatch false | touch false layout dispatch false | intercept false | touch false button dispatch true | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent false // 此处没有调用super.dispatchTouchEvent,直接返回了falseD/|activity *: onTouchEvent 0D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent falseD/|activity *: dispatchTouchEvent 1D/|activity *: onTouchEvent 1D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent false
loop end
!disallowIntercept
false
onInterceptTouchEvent
dispatchTouchEventreturn false
handled = dispatchTransformedTouchEvent();
dispatchTransformedTouchEvent
mGroupFlags |= FLAG_DISALLOW_INTERCEPT
li != null && li.mOnTouchListener != null&& (mViewFlags & ENABLED_MASK) == ENABLED&& span style=\"font-size: inherit;\
获取child
event.setAction(MotionEvent.ACTION_CANCEL)
true的话就return
window
dispatchTouchEventreturn true
dispatchTouchEvent
onUserInteraction()
!result && onTouchEvent(event)
onTouchEvent
continueloop
return handled
actionMasked == MotionEvent.ACTION_DOWN|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)||actionMasked == MotionEvent.ACTION_HOVER_MOVE
ViewGroup
predecessor = target;target = next;
newPointerIdBits == 0
handled = true
onFilterTouchEventForSecurity
组件
Activity
存在
不存在
activity dispatch false | touch false layout dispatch false | intercept false | touch false button dispatch false | touch trueD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: onInterceptTouchEvent 0D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 0D/| view *: onTouchEvent 0D/| view *: dispatchTouchEvent trueD/| layout *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent 1D/| layout *: dispatchTouchEvent 1D/| layout *: onInterceptTouchEvent 1D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 1D/| view *: onTouchEvent 1D/| view *: dispatchTouchEvent trueD/| layout *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent true
true
mFirstTouchTarget == null
事件
触发场景
单次事件流中触发的次数
MotionEvent.ACTION_DOWN
在屏幕按下时
1次
MotionEvent.ACTION_MOVE
在屏幕上滑动时
0次或多次
MotionEvent.ACTION_UP
在屏幕抬起时
0次或1次
MotionEvent.ACTION_CANCLE
滑动超出控件边界时
superDispatchTouchEvent(Window->PhoneWindow->DecorView)最终DecorView在superDispatchTouchEvent中调用父类FrameLayout的父类ViewGroup的dispatchTouchEvent
child.hasIdentityMatrix()
canceled|| actionMasked == MotionEvent.ACTION_HOVER_MOVE|| actionMasked == MotionEvent.ACTION_UP
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT
intercepted = onInterceptTouchEvent(ev)
removePointersFromTouchTargets()移除当前手指按下的View上的事件TouchTarget移除操作会让TouchTarget得到复用进入TouchTarget.sRecycleBin中
requestDisallowInterceptTouchEvent(boolean disallowIntercept)
transformedEvent.recycle();
trueloop
boolean flag = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0
handled = child.dispatchTouchEvent(event)
resetTouchState();
onTouchEventreturn true
actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && !result)
handled = child.dispatchTouchEvent(event);
点击时
newPointerIdBits == oldPointerIdBits
loop
disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0
result = true
handled = super.dispatchTouchEvent(transformedEvent);
return false
cancel
ListenerInfo li = mListenerInfo
alreadyDispatchedToNewTouchTarget && target == newTouchTarget
onFilterTouchEventForSecurity(event)
stopNestedScroll()
predecessor.next = next
return true
activity dispatch false | touch false layout dispatch false | intercept false | touch false button dispatch true | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: onInterceptTouchEvent 0D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent 1D/| layout *: dispatchTouchEvent 1D/| layout *: onInterceptTouchEvent 1D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 1D/| layout *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent true
事件分发顺序:流程图无法完整表达此逻辑,用文字表述1. activity、viewgroup、view核心方法: 1. dispatchTouchEvent 2. onTouchEvent 流程: 1. activity->viewgroup->view逐级传递dispatchTouchEvent 2. 当遇到某处dispatchTouchEvent return true的情况 view->viewgroup->activity逐级返回 dispatchTouchEvent 其中每个父节点的super.dispatchTouchEvent都会return true,并不再执行onTouchEvent 但是如果手动返回false,本节点不执行onTouchEvent,但是父节点还是会执行onTouchEvent 验证结果参照第一行最后两个特例2. 关于onInterceptTouchEvent onInterceptorTouchEvent是dispatchTouchEvent中拦截分发事件的方法 以下情况才会触发: 1. 是DOWN事件 或者 2. 事件链表中有View 满足以上条件并且 requestDisallowInterceptTouchEvent设置的是 false (根据(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0判断) 才会触发onInterceptorTouchEvent的回调,根据返回值确定是否要继续通过dispatchTouchEvent分发 也就是参与了部分确定super.dispatchTouchEvent返回值的工作,所以实际上onInterceptTouchEvent是dispatchTouchEvent中的一个小步骤
mNestedScrollingParent.onStopNestedScroll(this)
activity dispatch false | touch false layout dispatch false | intercept false | touch false button dispatch false | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: onInterceptTouchEvent 0D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 0D/| view *: onTouchEvent 0D/| view *: onTouchEvent falseD/| view *: dispatchTouchEvent falseD/| layout *: onTouchEvent 0D/| layout *: onTouchEvent falseD/| layout *: dispatchTouchEvent falseD/|activity *: onTouchEvent 0D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent falseD/|activity *: dispatchTouchEvent 1D/|activity *: onTouchEvent 1D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent false
activity dispatch false | touch false layout dispatch false | intercept true | touch false button dispatch false | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: onInterceptTouchEvent 0D/| layout *: onTouchEvent 0D/| layout *: onTouchEvent falseD/| layout *: dispatchTouchEvent falseD/|activity *: onTouchEvent 0D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent falseD/|activity *: dispatchTouchEvent 1D/|activity *: onTouchEvent 1D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent false
intercepted = false
transformedEvent = MotionEvent.obtain(event)
ViewGroupdispatchTouchEvent
child == null
ev.getAction() == MotionEvent.ACTION_DOWN
newTouchTarget != null如果child已经接收到事件
target != null
transformedEvent.transform(child.getInverseMatrix());
handled = super.dispatchTouchEvent(event)
mParent.requestDisallowInterceptTouchEvent(disallowIntercept)
activity dispatch false | touch false layout dispatch false | intercept false | touch true button dispatch false | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: onInterceptTouchEvent 0D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 0D/| view *: onTouchEvent 0D/| view *: onTouchEvent falseD/| view *: dispatchTouchEvent falseD/| layout *: onTouchEvent 0D/| layout *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent 1D/| layout *: dispatchTouchEvent 1D/| layout *: onTouchEvent 1D/| layout *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent true
disallowIntercept
dispatchTransformedTouchEvent()
activity dispatch false | touch false layout dispatch true | intercept false | touch false button dispatch false | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/|activity *: dispatchTouchEvent trueD/|activity *: dispatchTouchEvent 1D/| layout *: dispatchTouchEvent 1D/|activity *: dispatchTouchEvent true
removePointersFromTouchTargets()
switch action
mFirstTouchTarget = next
!canceled && !intercepted
!child.hasIdentityMatrix()
disallowIntercept == flag
activity dispatch true | touch false layout dispatch false | intercept false | touch false button dispatch false | touch falseD/|activity *: dispatchTouchEvent 0D/|activity *: dispatchTouchEvent 1
TouchTarget predecessor = nulltarget = mFirstTouchTarget
onInterceptTouchEventreturn true
target.recycle();target = next;
split && actionMasked == MotionEvent.ACTION_POINTER_UP
mTouchDelegate.onTouchEvent(event)
actionMasked ==MotionEvent.ACTION_DOWN||mFirstTouchTarget != null
cancelChild
actionMasked == MotionEvent.ACTION_DOWN
predecessor == null
transformedEvent = event.split(newPointerIdBits);
intercepted = true
TouchTarget next = target.next
(mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)
boolean result = false;
1. 如果某个组件的该方法返回TRUE: 则表示该组件已经对事件进行了处理,不用继续调用其余组件的分发方法 即停止分发2. 如果某个组件的该方法返回FALSE: 则表示该组件不能对该事件进行处理,需要按照规则继续分发事件。 在不复写该方法的情况下,除了一些特殊的组件,其余组件都是默认返回False的
dispatchTouchEventsuper返回值没有被return而是手动 return false
return result
特例:viewgroup的dispatchTouchEvent方法中调用super.dispatchTouchEvent 但不返回super的真实值true,而是直接返回false activity dispatch false | touch false layout dispatch false | intercept false | touch false button dispatch true | touch falseD/|activity *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent 0D/| layout *: onInterceptTouchEvent 0D/| layout *: onInterceptTouchEvent falseD/| view *: dispatchTouchEvent 0D/| layout *: dispatchTouchEvent true // 此处调用super.dispatchTouchEvent发现子节点消费了事件, 但是我们手动再返回false,告诉Activity没有消费,看结果D/|activity *: onTouchEvent 0D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent falseD/|activity *: dispatchTouchEvent 1D/|activity *: onTouchEvent 1D/|activity *: onTouchEvent falseD/|activity *: dispatchTouchEvent false
0 条评论
下一页