1、android 事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。
2、在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递, 返回false代表不对事件拦截。
3、子View中如果将传递的事件消费掉,ViewGroup将无法接收到任何事件。
4、super.onInterceptTouchEvent(ev)默认为FALSE
5、事件传递机制的步骤:
5.1、view执行dispatchTouchEvent方法,开始分发事件
5.2、执行onInterceptTouchEvent判断是否中断事件分发
4.3、执行onTouchEvent方法,去处理事件
6、touch事件处理流程图
7、多点触控事件
在android的中,MotionEvent event代表的是一个触摸事件。我们对屏幕的几乎所有操作都会触发该事件,如点击、放开、滑动等。不同的事件在MotionEvent中有不同的id,根据id的不同可以判断触摸事件属于哪个手指。
在MotionEvent类中有两个参数可以用来获取对触摸的控制,这两个参数分别为:MotionEvent.getAction()和MotionEvent.ACTION_MASK,前者用于对单点触控进行操作,后者用于对多点触控进行操作,相应地,我们可以通过Android Developers’ Reference看到,对于单点触控,我们由MotionEvent.getAction()可以得到以下几种事件:ACTION_DOWN、ACTION_UP,而对于多点触控,由MotionEvent.ACTION_MASK,我们可以得到:ACTION_POINTER_DOWN、ACTION_POINTER_UP,都是MotionEvent中的常量,可以直接调用。而有些常量则是单点和多点共用的,如:ACTION_MOVE,因此在按下时,我们必须标记单点与多点触控的区别。
下面将介绍一下上面提到的五个操作:
- MotionEvent.ACTION_DOWN:在第一个点被按下时触发
- MotionEvent.ACTION_UP:当屏幕上唯一的点被放开时触发
- MotionEvent.ACTION_POINTER_DOWN:当屏幕上已经有一个点被按住,此时再按下其他点时触发。
- MotionEvent.ACTION_POINTER_UP:当屏幕上有多个点被按住,松开其中一个点时触发(即非最后一个点被放开时)。
- MotionEvent.ACTION_MOVE:当有点在屏幕上移动时触发。值得注意的是,由于它的灵敏度很高,而我们的手指又不可能完全静止(即使我们感觉不到移动,但其实我们的手指也在不停地抖动),所以实际的情况是,基本上只要有点在屏幕上,此事件就会一直不停地被触发。
举例来讲:当我们放一个食指到屏幕上时,触发ACTION_DOWN事件;再放一个拇指到屏幕上,触发ACTION_POINTER_DOWN事件;此时再把食指或拇指放开,都会触发ACTION_POINTER_UP事件;再放开最后一个手指,触发ACTION_UP事件;而同时在整个过程中,ACTION_MOVE事件会一直不停地被触发。例子代码如下所示:
/** * 多指操作时,为了避免多个事件进行响应,当多个点被按住时,阻止事件向下分发 * * */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub switch (ev.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: //在第一个点被按下时触发 case MotionEvent.ACTION_UP: //当屏幕上唯一的点被放开时触发 case MotionEvent.ACTION_POINTER_UP: //当屏幕上有多个点被按住,松开其中一个点时触发(即非最后一个点被放开时)。 break; case MotionEvent.ACTION_POINTER_DOWN: //当屏幕上已经有一个点被按住,此时再按下其他点时触发。 return true; //中断事件向下分发 } return false; //触摸事件继续向下分发 }
8、一个自定义的LinearLayout的代码
package com.example.pinterestlistview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; public class MyLinearLayout extends LinearLayout { public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true; //中断事件向下分发 } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("fuyanan", "yanan:"+super.dispatchTouchEvent(ev)); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { int width=getWidth()/getChildCount(); int height = getHeight(); int count=getChildCount(); Log.i("fuyanan", "yanan:"+count); float eventX = event.getX(); if (eventX<width){ // 滑动左边的 listView event.setLocation(width/2, event.getY()); Log.i("fuyanan", "yanan:"+getChildAt(0)); getChildAt(0).dispatchTouchEvent(event); // 事件分发给第一个孩子 return true; } else if (eventX > width && eventX < 2 * width) { //滑动中间的 listView float eventY = event.getY(); if (eventY < height / 2) { event.setLocation(width / 2, event.getY()); for (int i = 0; i < count; i++) { View child = getChildAt(i); try { child.dispatchTouchEvent(event); 事件分发给所有的孩子 } catch (Exception e) { e.printStackTrace(); } } return true; } else if (eventY > height / 2) { event.setLocation(width / 2, event.getY()); try { getChildAt(1).dispatchTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } return true; } }else if (eventX>2*width){ event.setLocation(width/2, event.getY()); getChildAt(2).dispatchTouchEvent(event); 事件分发给第三个孩子 return true; } return true; //消耗此事件 } }