Android事件分发原理

一、事件分发机制流程图

当点击view的时候,最先响应的是它的父容器viewGroup,执行事件分发dispatchTouchEvent(MotionEvent e),在这个方法的内部会走它自身的onInterceptTouchEvent(MotionEvent e)进行事件拦截判断,如果该方法返回值为true(进行拦截),则该事件不会传递给它的子view,会走到viewGroup的onTouchEvent(MotionEvent e)事件;如果该方法返回为false(不进行拦截),则会传递给子view,子view的dispatchTouchEvent(MotionEvent e)方法执行,因为子view没有孩子,所以它没有onInterceptTouchEvent(MotionEvent e)拦截方法,而是直接走到onTouchEvent(MotionEvent e)事件,返回true,则表明消费该事件,父容器viewGroup的onTouchEvent(MotionEvent e)不会执行;如果子view的onTouchEvent(MotionEvent e)事件返回false,则表明不消费该事件,往上抛给它的父容器viewGroup,父容器的onTouchEvent(MotionEvent e)事件会执行。以此类推,树状结果,从根部开始往下遍历,走到子view的onTouchEvent(MotionEvent e),根据它的返回结果,反馈给它的父容器。
在这里插入图片描述
上述流程中有关onTouch(View v, MotionEvent event)和onClick()方法进行说明:

  • 如果View或者ViewGroup设置了View.OnTouchListener()事件,则在执行onTouchEvent(MotionEvent event)之前会执行onTouch(View v, MotionEvent event)方法,它的返回结果决定onTouchEvent(MotionEvent event)是否执行,返回false,则执行onTouchEvent(MotionEvent event);返回true,则不执行onTouchEvent(MotionEvent event)。

  • onClick()事件类似,前提是设置了View.OnClickListener()事件,且执行了performClick()事件,performClick()方法的执行依赖于onTouchEvent(MotionEvent event)方法的返回值,为true,则执行performClick();为false,则不执行performClick(),也就不会执行onClick()方法了。

二、View的滑动冲突

1.常见滑动冲突场景
  • 外部滑动方向与内部滑动方向不一致,比如ViewPager中包含ListView
  • 外部滑动方向与内部滑动方向一致,比如ScrollView中包含ListView
2.滑动冲突处理规则

通过判断是水平滑动还是竖直滑动来判断到底应该谁来拦截事件;可以根据水平和竖直两个方向的距离差或速度差来做判断。

3.滑动冲突解决方式?
  • 外部拦截法: 即点击事件先经过父容器的拦截处理,如果父容器需要此事件就拦截,不需要就不拦截,需要重写父容器的onInterceptTouchEvent方法;在onInterceptTouchEvent方法中,首先ACTION_DOWN这个事件,父容器必须返回false,即不拦截ACTION_DOWN事件,因为一旦父容器拦截了ACTION_DOWN,那么后续的ACTION_MOVE/ACTION_UP都会直接交给父容器处理;其次是ACTION_MOVE,根据需求来决定是否要拦截;最后ACTION_UP事件,这里必须要返回false,在这里没有多大意义。
  • 内部拦截法: 所有事件都传递给子元素,如果子元素需要就消耗掉,不需要就交给父元素处理,需要子元素配合requestDisallowInterceptTouchEvent方法才能正常工作;父元素需要默认拦截除ACTION_DOWN以外的事件,这样子元素调用parent.requestDisallowInterceptTouchEvent(false)方法时,父元素才能继续拦截需要的事件。(ACTION_DOWN事件不受requestDisallowInterceptTouchEvent方法影响,所以一旦父元素拦截ACTION_DOWN事件,那么所有元素都无法传递到子元素去)。

猜你喜欢

转载自blog.csdn.net/weixin_42600398/article/details/123601404
今日推荐