• (二十五)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;   //消耗此事件
        }
        
    }
  • 相关阅读:
    如何高效的利用博客园?
    [Asp.net]常见数据导入Excel,Excel数据导入数据库解决方案,总有一款适合你!
    [c#基础]关于const和readonly常见的笔试题剖析
    [Asp.net]常见word,excel,ppt,pdf在线预览方案,有图有真相,总有一款适合你!
    [c#基础]关于try...catch最常见的笔试题
    [UML]UML系列——时序图(顺序图)sequence diagram
    [转]winscp以命令行方式同步服务器数据到PC机磁盘上
    Mysql配置参数说明
    安装最新Nginx
    [CentOS7]redis设置开机启动,设置密码
  • 原文地址:https://www.cnblogs.com/fuyanan/p/4152082.html
Copyright © 2020-2023  润新知