zoukankan      html  css  js  c++  java
  • Android触控屏幕GestureDetector和SimpleOnGestureListener详解

    本文来自多出合成:

    http://www.apkbus.com/forum.php?mod=viewthread&tid=53000

    http://www.linuxidc.com/Linux/2011-09/42265.htm

    1. 当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)Android sdk给我们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的,因此这个类对外提供了两个接口:OnGestureListener,OnDoubleTapListener,还有一个内部类SimpleOnGestureListener,SimpleOnGestureListener类是GestureDetector提供给我们的一个更方便的响应不同手势的类,这个类实现了上述两个接口(但是所有的方法体都是空的),该类是static class,也就是说它实际上是一个外部类。程序员可以在外部继承这个类,重写里面的手势处理方法。
    通过GestureDetector的构造方法可以将SimpleOnGestureListener对象传递进去,这样GestureDetector能处理不同的手势了。
    2. 具体用法:
    2.1

    1. private class DefaultGestureListener extends SimpleOnGestureListener{
    2.         @Override
    3.         public boolean onSingleTapUp(MotionEvent e) {
    4.             return false;
    5.         }
    6.         @Override
    7.         public void onLongPress(MotionEvent e) {
    8.             
    9.         }
    10.         /**
    11.          * @param e1 The first down motion event that started the scrolling.
    12.            @param e2 The move motion event that triggered the current onScroll.
    13.            @param distanceX The distance along the X axis(轴) that has been scrolled since the last call to onScroll. This is NOT the distance between e1 and e2.
    14.            @param distanceY The distance along the Y axis that has been scrolled since the last call to onScroll. This is NOT the distance between e1 and e2.
    15.                        无论是用手拖动view,或者是以抛的动作滚动,都会多次触发 ,这个方法在ACTION_MOVE动作发生时就会触发 参看GestureDetector的onTouchEvent方法源码
    16.          * */
    17.         @Override
    18.         public boolean onScroll(MotionEvent e1, MotionEvent e2,
    19.                 float distanceX, float distanceY) {
    20.             return false;
    21.         }
    22.         /**
    23.          * @param e1 第1个ACTION_DOWN MotionEvent 并且只有一个
    24.          * @param e2 最后一个ACTION_MOVE MotionEvent
    25.          * @param velocityX X轴上的移动速度,像素/秒  
    26.          * @param velocityY Y轴上的移动速度,像素/秒
    27.          * 这个方法发生在ACTION_UP时才会触发 参看GestureDetector的onTouchEvent方法源码
    28.          *
    29.          * */
    30.         @Override
    31.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
    32.                 float velocityY) {
    33.             return false;
    34.         }
    35.         @Override
    36.         public void onShowPress(MotionEvent e) {
    37.             
    38.         }
    39.         @Override
    40.         public boolean onDown(MotionEvent e) {
    41.             return false;
    42.         }
    43.         @Override
    44.         public boolean onDoubleTap(MotionEvent e) {
    45.             return false;
    46.         }
    47.         @Override
    48.         public boolean onDoubleTapEvent(MotionEvent e) {
    49.             return false;
    50.         }
    51.         /**
    52.          * 这个方法不同于onSingleTapUp,他是在GestureDetector确信用户在第一次触摸屏幕后,没有紧跟着第二次触摸屏幕,也就是不是“双击”的时候触发
    53.          * */
    54.         @Override
    55.         public boolean onSingleTapConfirmed(MotionEvent e) {
    56.             return false;
    57.         }
    58.         
    59.     }
    复制代码

    2.2  public GestureDetector (Context context, GestureDetector.OnGestureListener listener)通过构造方法将手势响应交给手势识别类
    2.3  在OnTouchListener的onTouch方法中

    1. private OnTouchListener gestureTouchListener = new OnTouchListener() {
    2.         @Override
    3.         public boolean onTouch(View v, MotionEvent event) {
    4.             return gDetector.onTouchEvent(event);
    5.         }
    6.     };
    复制代码

    ok,到此为止就结束了
    遇到的问题:
    1. onFling(***)无法触发
         通过设置 mListView.setLongClickable(true);即可(我处理的是ListView的手势事件),只有这样,view才能够处理不同于Tap(轻触)的hold(即ACTION_MOVE,或者多个ACTION_DOWN),我们同样可以通过layout定义中的android:longClickable来做到这一点。
    2. 用户长按手机屏幕,就会触发长按事件,离开屏幕时,就会触发up事件,但是SimpleOnGestureListener没有对longPress事件的up事件对外提供接口
    解决办法:
    类似于这样,截获up事件,因为所有的都是有OnTouchListener 先获得,然后传递给SimpleOnGestureListener的,这里有一点必须要注意:
    截获到up事件,我们进行了处理后,必须要将这个事件再交给SimpleOnGestureListener处理,虽然我们只截获长按事件的up,但是SimpleOnGestureListener对于长按事件的up也做了一些处理,只是没有对外提供接口。
    做了什么处理:

    1. if (mInLongPress) {
    2.                 mHandler.removeMessages(TAP);
    3.                 mInLongPress = false;
    4. }
    5. 如果不交给SimpleOnGestureListener处理,那么单击动作也会触发onLongPress方法。
    6. private OnTouchListener gestureTouchListener = new OnTouchListener() {
    7.         @Override
    8.         public boolean onTouch(View v, MotionEvent event) {
    9.             switch (event.getAction()) {
    10.             case MotionEvent.ACTION_DOWN:
    11.                 return gDetector.onTouchEvent(event);
    12.            case MotionEvent.ACTION_UP:
    13.                 MyGesture.FlagInfo info = mGesture.getFlagInfo();
    14.                 if(info.isConnected==true){
    15.                     int firstVisiblePosition = mListView.getFirstVisiblePosition();
    16.                     View view = mListView.getChildAt(info.position-firstVisiblePosition);
    17.                     if(view!=null){
    18.                         view.setBackgroundResource(R.drawable.listitem_background_blue);
    19.                         info.isConnected = false;
    20.                     }
    21.                 }
    22.                 return gDetector.onTouchEvent(event);
    23.             case MotionEvent.ACTION_MOVE:
    24.                 return gDetector.onTouchEvent(event);
    25.             }
    26.             return false;
    27.             
    28.         }
    29.     };
    复制代码

    总结:
    1. 点击屏幕上的某项的执行流程  有两种情况,一种是时间很短,一种时间稍长
    时间很短:onDown--------》onSingleTapUp--------》onSingleTapConfirmed
    时间稍长:onDown--------》onShowPress------》onSingleTapUp--------》onSingleTapConfirmed
    2. 长按事件
    onDown--------》onShowPress------》onLongPress
    3.抛:手指触动屏幕后,稍微滑动后立即松开
    onDown-----》onScroll----》onScroll----》onScroll----》………----->onFling
    4.拖动
    onDown------》onScroll----》onScroll------》onFiling
    注意:有的时候会触发onFiling,但是有的时候不会触发,个人理解是人的动作不标准所致。

    当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)Android sdk给我们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的,因此这个类对外提供了两个接口:OnGestureListener,OnDoubleTapListener,还有一个内部类SimpleOnGestureListener,SimpleOnGestureListener类是GestureDetector提供给我们的一个更方便的响应不同手势的类,这个类实现了上述两个接口(但是所有的方法体都是空的),该类是static class,也就是说它实际上是一个外部类。程序员可以在外部继承这个类,重写里面的手势处理方法。

    通过GestureDetector的构造方法可以将SimpleOnGestureListener对象传递进去,这样GestureDetector能处理不同的手势了。

    2.、具体用法:

    /** 
     * 当我们捕捉到Touch操作的时候,如何识别出用户的Gesture?这里我们需要GestureDetector.OnGestureListener接口的帮助 
     *  
     * @author HB 
     */  
    public class MySurfaceView extends SurfaceView implements OnGestureListener,  
            OnTouchListener, Callback {  
        GestureDetector gd;  
        Context context;  
      
        public MySurfaceView(Context context) {  
            super(context);  
            this.context = context;  
            setFocusable(true);  
            requestFocus();  
            this.setLongClickable(true);  
            this.setOnTouchListener(this);  
            setFocusable(true);  
            gd = new GestureDetector(new MySimpleGesture());// 这里或者可以直接传递this参数,因为本类已经继承了OnGestureListener接口,也可以把new   
                                                            // MySimpleGesture(),它继承了SimpleOnGestureListener类;,两种方法都可以,只是把两种方法归在一个里面,方便学习;   
                                                            // 。实惠屏幕触控事件;   
            gd.setIsLongpressEnabled(true);  
            // TODO Auto-generated constructor stub   
        }  
      
        // 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发   
        @Override  
        public boolean onDown(MotionEvent e) {  
            // TODO Auto-generated method stub   
            System.out.println("onDown");  
            return false;  
        }  
      
        /* 
         * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发 
         * 注意和onDown()的区别,强调的是没有松开或者拖动的状态 (单击没有松开或者移动时候就触发此事件,再触发onLongPress事件) 
         */  
        @Override  
        public void onShowPress(MotionEvent e) {  
            // TODO Auto-generated method stub   
            System.out.println("onShowPress");  
        }  
      
        // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发   
        @Override  
        public boolean onSingleTapUp(MotionEvent e) {  
            // TODO Auto-generated method stub   
            System.out.println("onSingleTopUp");  
            return false;  
        }  
      
        // 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发   
        @Override  
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,  
                float distanceY) {  
            System.out.println("onScroll");  
            // TODO Auto-generated method stub   
            return false;  
        }  
      
        // 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发   
        @Override  
        public void onLongPress(MotionEvent e) {  
            // TODO Auto-generated method stub   
            System.out.println("onLongPress");  
        }  
      
        /* 
         * 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 
         * 1个ACTION_UP触发(non-Javadoc) 
         * Fling事件的处理代码:除了第一个触发Fling的ACTION_DOWN和最后一个ACTION_MOVE中包含的坐标等信息外 
         * ,我们还可以根据用户在X轴或者Y轴上的移动速度作为条件 
         * 比如下面的代码中我们就在用户移动超过100个像素,且X轴上每秒的移动速度大于200像素时才进行处理。 
         *  
         * @see android.view.GestureDetector.OnGestureListener#onFling(android.view. 
         * MotionEvent, android.view.MotionEvent, float, float) 
         * 这个例子中,tv.setLongClickable( true )是必须的,因为 
         * 只有这样,view才能够处理不同于Tap(轻触)的hold(即ACTION_MOVE,或者多个ACTION_DOWN) 
         * ,我们同样可以通过layout定义中的android:longClickable来做到这一点 
         */  
        @Override  
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
                float velocityY) {  
            // TODO Auto-generated method stub   
            System.out.println("onFling");  
            // 参数解释:   
            // e1:第1个ACTION_DOWN MotionEvent   
            // e2:最后一个ACTION_MOVE MotionEvent   
            // velocityX:X轴上的移动速度,像素/秒   
            // velocityY:Y轴上的移动速度,像素/秒   
      
            // 触发条件 :   
            // X轴的坐标位移大于FLING_MIN_DISTANCE,且移动速度大于FLING_MIN_VELOCITY个像素/秒   
            final int FLING_MIN_DISTANCE = 100, FLING_MIN_VELOCITY = 200;  
            if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE  
                    && Math.abs(velocityX) > FLING_MIN_VELOCITY) {  
                // Fling left   
                Log.i("MyGesture", "Fling left");  
                Toast.makeText(context, "Fling Left", Toast.LENGTH_SHORT).show();  
            } else if (e2.getX() - e1.getX() > FLING_MIN_DISTANCE  
                    && Math.abs(velocityX) > FLING_MIN_VELOCITY) {  
                // Fling right   
                Log.i("MyGesture", "Fling right");  
                Toast.makeText(context, "Fling Right", Toast.LENGTH_SHORT).show();  
            }  
            return true;  
        }  
      
        /** 
         * 当发行屏幕触控事件的时候,首先出发此方法,再通过此方法,监听具体的整件 
         * 在onTouch()方法中,我们调用GestureDetector的onTouchEvent 
         * ()方法,将捕捉到的MotionEvent交给GestureDetector 来分析是否有合适的callback函数来处理用户的手势 
         */  
        @Override  
        public boolean onTouch(View v, MotionEvent event) {  
            // TODO Auto-generated method stub   
            System.out.println("onTouch");  
            return gd.onTouchEvent(event);  
        }  
      
        @Override  
        public void surfaceCreated(SurfaceHolder holder) {  
            // TODO Auto-generated method stub   
      
        }  
      
        @Override  
        public void surfaceChanged(SurfaceHolder holder, int format, int width,  
                int height) {  
            // TODO Auto-generated method stub   
      
        }  
      
        @Override  
        public void surfaceDestroyed(SurfaceHolder holder) {  
            // TODO Auto-generated method stub   
      
        }  
      
        /** 
         * SimpleOnGestureListener implements GestureDetector.OnDoubleTapListener, 
         * GestureDetector.OnGestureListener 
         */  
        private class MySimpleGesture extends SimpleOnGestureListener {  
            // 双击的第二下Touch down时触发   
            public boolean onDoubleTap(MotionEvent e) {  
                Log.i("MyGesture", "onDoubleTap");  
                return super.onDoubleTap(e);  
            }  
      
            // 双击的第二下Touch down和up都会触发,可用e.getAction()区分   
            public boolean onDoubleTapEvent(MotionEvent e) {  
                Log.i("MyGesture", "onDoubleTapEvent");  
                return super.onDoubleTapEvent(e);  
            }  
      
            // Touch down时触发   
            public boolean onDown(MotionEvent e) {  
                Log.i("MyGesture", "onDown");  
                return super.onDown(e);  
            }  
      
            // Touch了滑动一点距离后,up时触发   
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
                    float velocityY) {  
                Log.i("MyGesture", "onFling");  
                return super.onFling(e1, e2, velocityX, velocityY);  
            }  
      
            // Touch了不移动一直Touch down时触发   
            public void onLongPress(MotionEvent e) {  
                Log.i("MyGesture", "onLongPress");  
                super.onLongPress(e);  
            }  
      
            // Touch了滑动时触发   
            public boolean onScroll(MotionEvent e1, MotionEvent e2,  
                    float distanceX, float distanceY) {  
                Log.i("MyGesture", "onScroll");  
                return super.onScroll(e1, e2, distanceX, distanceY);  
            }  
      
            /* 
             * Touch了还没有滑动时触发 (1)onDown只要Touch Down一定立刻触发 (2)Touch 
             * Down后过一会没有滑动先触发onShowPress再触发onLongPress So: Touch Down后一直不滑动,onDown 
             * -> onShowPress -> onLongPress这个顺序触发。 
             */  
            public void onShowPress(MotionEvent e) {  
                Log.i("MyGesture", "onShowPress");  
                super.onShowPress(e);  
            }  
      
            /* 
             * 两个函数都是在Touch Down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touch Up时触发 
             * 点击一下非常快的(不滑动)Touch Up: onDown->onSingleTapUp->onSingleTapConfirmed 
             * 点击一下稍微慢点的(不滑动)Touch Up://确认是单击事件触发 
             * onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed 
             */  
            public boolean onSingleTapConfirmed(MotionEvent e) {  
                Log.i("MyGesture", "onSingleTapConfirmed");  
                return super.onSingleTapConfirmed(e);  
            }  
      
            public boolean onSingleTapUp(MotionEvent e) {  
                Log.i("MyGesture", "onSingleTapUp");  
                return super.onSingleTapUp(e);  
            }  
        }  

    本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-09/42265.htm

  • 相关阅读:
    hihoCoder #1062 : 最近公共祖先·一
    hihoCoder #1050 : 树中的最长路
    hihoCoder #1049 : 后序遍历
    108 Convert Sorted Array to Binary Search Tree 将有序数组转换为二叉搜索树
    107 Binary Tree Level Order Traversal II 二叉树的层次遍历 II
    106 Construct Binary Tree from Inorder and Postorder Traversal 从中序与后序遍历序列构造二叉树
    105 Construct Binary Tree from Preorder and Inorder Traversal 从前序与中序遍历序列构造二叉树
    104 Maximum Depth of Binary Tree 二叉树的最大深度
    102 Binary Tree Level Order Traversal 二叉树的层次遍历
    101 Symmetric Tree 判断一颗二叉树是否是镜像二叉树
  • 原文地址:https://www.cnblogs.com/crazywenza/p/2801327.html
Copyright © 2011-2022 走看看