事件分发
- 用户通过屏幕与手机交互的时候,每一次点击、长按、移动等都是一个事件
- 事件分发机制:某一个事件从屏幕传递各个View,由View来使用这一个事件(消费事件)或者忽略这一事件(不消费事件),这整个过程的控制
事件传递层级
Activity->Window->DecorView->ViewGroup->View
首先再Activity上,传递给Activity持有的window,接着传递给window持有的DecorView,DecorView继承自ViewGroup然后真正分发到ViewGroup和View上面
Activity中事件传递过程
通过方法:
- dispatchTouchEvent(MovtionEvent ev)
- onTouchEvent(MovtionEvent ev)
- Activity事件开始的时候会首先调用dispatchTouchEvent()方法
- 如果为事件为Down按下,Activity下有个方法会被调用(onUserInteraction()),需要用的话重新就行
- 接下来会调用getWindow().superDispatchTouchEvent(ev)方法,从这里正式进入事件派发过程,一直会调用到ViewGroup的dispatchTouchEvent()方法
- 如果返回为true,Activity的dispatchTouchEvent()方法也会返回为true表示事件被消费
- 如果返回为false,就会调用Activity的onTouchEvent()方法
- Activity的onTouchEvent()方法首先会调用Window下的shouldCloseOnTouch()方法,判断事件是否再可响应范围内,返回true和false,Activity的dispatchTouchEvent()方法的返回值等于Activity.onTouchEvent()方法返回值,并结束事件
ViewGroup事件分发
使用方法:
- dispatchTouchEvent()
- onInterceptTouchEvent()
- onTouchEvent()
- 在ViewGroup.dispatchTouchEvent()方法进入
- 然后调用onFilterTouchEventForSecurity(),判断触摸事件是否符合安全策略,返回false未消费,结束事件
- 安全策略之后之后如果当前触摸事件是down按下事件系统会清除所有的触摸目标,并且重置触摸状态
- 返回true执行onIntercepTouchEvent()方法,判断是否拦截(按下事件或者存在子view的时候进入逻辑)
- 不去拦截返回false允许向子View传递,找到被点击的子View,调用子View的dispatchTouchEvent()方法,结束事件
- 拦截返回true,不允许事件向子View传递,调用ViewGroup父类的dispatchTouchEvent()方法自己处理该事件,结束事件
ViewGroup安全策略
onFilterTouchEventForSecurity()
1. 当前view是否处于被遮挡的状态,
2. 当前的配置是否设置成被遮挡时过滤触摸事件
View 事件分发
- dispatchTouchEvent()
- onTouchEvent()
- 在View.dispatchTouchEvent() 方法进入,首先判断当前的View是否具有响应的焦点,如果没有响应方法直接返回false事件未消费
- 如果可响应返回true,执行onFilterTouchEventforSecurity(),判断触摸事件是否符合安全策略
- 接着判断是否为鼠标事件,如果是返回true标记事件被消费
- 如果不是鼠标事件,系统就会判断当前view是否已经注册了TouchListener(触摸监听),监听onTouch()触摸事件的返回值
- 返回值为true事件被消费,系统就会监听view的onTuchEvent()触摸事件返回值,触摸事件的返回值,返回true被消费,false未消费结束事件
事件分发总结
Activity->Window->DecorView->ViewGroup->View
传递阶层:DecorView:是Activity最顶层的View视图,DecorView继承自FrameLayout,继承自ViewGroup
首先再Activity上,传递给Activity持有的window窗口,接着传递给window持有的DecorView,DecorView继承自ViewGroup然后真正分发到一个个的ViewGroup和View上面
第一部分Activity
- Activity事件开始的时候会首先调用dispatchTouchEvent()方法
- 如果为事件为Down按下,首先会调用onUserInteraction(),这是一个空方法需要用的话重写即可
- 接下来会调用getWindow().superDispatchTouchEvent(ev)方法,从这里正式进入事件派发过程,一直会调用到ViewGroup的dispatchTouchEvent()方法,如果这个方法返回为true,Activity的dispatchTouchEvent()方法也会返回为true表示事件被消费
- 如果返回为false,就会调用Activity的onTouchEvent()方法,方法首先会调用Window下的shouldCloseOnTouch()方法,判断事件是否再可响应范围内,返回true和false,返回结果等于Activity的dispatchTouchEvent()方法分发事件的返回结果
第二部分ViewGroup
- 在ViewGroup.dispatchTouchEvent()方法进入
- 然后调用onFilterTouchEventForSecurity(),判断触摸事件是否符合安全策略,返回false未消费,结束事件
- 进入viewGroup,经过安全策略,之后系统会判断当前触摸事件是按下的时候会清除所有的触摸目标,并且重置触摸状态。之后系统进行检测当时触摸事件是否需要拦截(等于按下事件Down或者存在子View)
- 返回true执行onIntercepTouchEvent()方法,判断是否拦截(按下事件或者存在子view的时候进入逻辑)
- 不去拦截返回false允许向子View传递,找到被点击的子View,调用子View的dispatchTouchEvent()方法,结束事件
- 拦截返回true,不允许事件向子View传递,调用ViewGroup父类的dispatchTouchEvent()方法自己处理该事件,结束事件
第三部分View
- 在View.dispatchTouchEvent() 方法进入,首先判断当前的View是否具有响应的焦点,如果没有响应方法直接返回false事件未消费
- 如果可响应返回true,执行onFilterTouchEventforSecurity(),判断触摸事件是否符合安全策略
- 接着判断是否为鼠标事件,如果是返回true标记事件被消费
- 如果不是鼠标事件,系统就会判断当前view是否已经注册了TouchListener(触摸监听),监听onTouch()触摸事件的返回值
- 返回值为true事件被消费,系统就会监听view的onTuchEvent()触摸事件返回值,触摸事件的返回值,返回true被消费,false未消费结束事件