简述
所谓点击事件的事件分发,其实就是对MotionEvent事件的分发过程
当一个点击事件产生后,它的传递过程遵循如下顺序:Activity -> PhoneWindow->decor View -> ViewGroup -> 子ViewGroup ->子View…,如果一个decor View接收到事件后,就会按照事件分发机制去发分事件。事件的分发过程由三个很重要的方法来共同完成:
- dispatchTouchEvent、
- onInterceptTouchEvent
- onTouchEvent
一、原理
- 要点总结:
触摸事件有一个down,多个move,一个up组成;
事件的传递是从Activity开始的 - Activity -->PhoneWindow–>DectorView–>ViewGroup–>View;主要操作在ViewGroup和View中;
ViewGroup类主要调用:dispatchTouchEvent()–>onInterceptTouchEnent()–>dispatchTransformedTouchEvent();ViewGroup不直接调用onTouchEvent()方法;
-
执行优先级:OnTouchListener的onTouch() > onTouchEvent() > onClick();
-
事件的传递顺序:
二、能解决什么问题?
1. 场景1 listview去下拉 , 误item点击
一个页面,可下拉刷新,有listview。当你触摸listview去下拉的时候,以松手,哎呀?!怎么自己跳item点击了。下面说一下解决办法。
2. 场景2 ScrollView 嵌套了垂直的ListView 滑动卡顿;
-
背景: ScrollView里嵌套了一个垂直的ListView或者RecycleView会出现滑动卡顿的问题.
-
原因: 是ScrollView的滑动事件与子View(ListView或者RecycleView)的滑动发生了冲突.
-
解决方法 1(外部拦截法): 自定义ScrollView,判断滑动的意图是垂直滑动还是水平滑动.
public class MyScrollView extends ScrollView { public MyScrollView(Context context) { super(context); } public MyScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private int x, y; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN://按下y x = (int) ev.getX(); y = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE://移动 int new_x = (int) ev.getX(); int new_y = (int) ev.getY(); //判断有水平滑动的意向 int move_x = Math.abs(new_x - x);//x轴滑动的距离 int move_y = Math.abs(new_y - y);//y轴滑动的距离 if (move_x > (move_y + 10))//10的偏移量 , 如果是水平滑动,刚拦截 { return true;//拦截 }else{ return false; //传递给字View } break; } return super.onInterceptTouchEvent(ev); }
- 解决方法 2 (内部拦截法): 先重写自定义view的dispatchTouchEvent方法 --待述