(二十五)touch事件消息传递

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;   //消耗此事件
    }
    
}
原文地址:https://www.cnblogs.com/fuyanan/p/4152082.html