zoukankan      html  css  js  c++  java
  • Android Gesture Detector

    Android Touch Screen 与传统Click Touch Screen不同,会有一些手势(Gesture),例如Fling,Scroll等等。这些Gesture会使用户体验大大提升。Android中的Gesture识别(detector)是通过GestureDetector.OnGestureListener接口实现的。

    首先,Android事件处理机制是基于Listener实现的,比如触摸屏相关的事件,就是通过onTouchListener实现;

    其次,所有View的子类都可以通过setOnTouchListener()、setOnKeyListener()等方法来添加对某一类事件的Listener;

    第三,Listener一般会以Interface的方式来提供,其中包含一个或多个abstract方法,我们需要实现这些方法来完成onTouch()、onKey()等操作。这样,程序便可以在特定的事件被dispatch到该view的时候,通过callback函数给予适当的响应。

    1. Touch Screen Click举例

    复制代码
    public class MyGesture extends Activity implements OnTouchListener {
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            TextView tv = (TextView) findViewById(R.id.tv);
            tv.setOnTouchListener(this);
        }
        public boolean onTouch(View v, MotionEvent event) {
            Toast.makeText(this, "Touch Touch", Toast.LENGTH_SHORT).show();
            return false;
        }
    }
    复制代码

    我们可以通过MotionEvent的getAction()方法来获取Touch事件的类型,包括 ACTION_DOWN(按下触摸屏),ACTION_MOVE(按下触摸屏后移动受力点), ACTION_UP(松开触摸屏)和ACTION_CANCEL(不会由用户直接触发)。借助对于用户不同操作的判断,结合getRawX()、getRawY()、getX()和getY()等方法来获取坐标后,我们可以实现诸如拖动某一个按钮,拖动滚动条等功能。

    2. 回到今天的重点,当我们捕捉到Touch操作的时候,如何识别出用户的Gesture?这里我们需要GestureDetector.OnGestureListener接口的帮助,代码如下:

    复制代码
    public class MyGesture extends Activity implements OnTouchListener, OnGestureListener {
        private GestureDetector mGestureDetector;
        public MyGesture() {
            mGestureDetector = new GestureDetector(this);
        }
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            TextView tv = (TextView) findViewById(R.id.tv);
            tv.setOnTouchListener(this);
            tv.setFocusable(true);
            tv.setClickable(true);
            tv.setLongClickable(true);
            mGestureDetector.setIsLongpressEnabled(true);
        }
        
        /*
         * 在onTouch()方法中,我们调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给GestureDetector
         * 来分析是否有合适的callback函数来处理用户的手势
         */public boolean onTouch(View v, MotionEvent event) {
            return mGestureDetector.onTouchEvent(event);
        }
    
        // 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发public boolean onDown(MotionEvent arg0) {
            Log.i("MyGesture", "onDown");
            Toast.makeText(this, "onDown", Toast.LENGTH_SHORT).show();
            return true;
        }
        
        /*
         * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发
         * 注意和onDown()的区别,强调的是没有松开或者拖动的状态
         */public void onShowPress(MotionEvent e) {
            Log.i("MyGesture", "onShowPress");
            Toast.makeText(this, "onShowPress", Toast.LENGTH_SHORT).show();
        }
        
        // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发public boolean onSingleTapUp(MotionEvent e) {
            Log.i("MyGesture", "onSingleTapUp");
            Toast.makeText(this, "onSingleTapUp", Toast.LENGTH_SHORT).show();
            return true;
        }
        
        // 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            Log.i("MyGesture", "onFling");
            Toast.makeText(this, "onFling", Toast.LENGTH_LONG).show();
            return true;
        }
        
        // 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            Log.i("MyGesture", "onScroll");
            Toast.makeText(this, "onScroll", Toast.LENGTH_LONG).show();
            return true;
        }
        
        // 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发public void onLongPress(MotionEvent e) {
            Log.i("MyGesture", "onLongPress");
            Toast.makeText(this, "onLongPress", Toast.LENGTH_LONG).show();
        }
    }
    复制代码

    3. Fling事件的处理代码:除了第一个触发Fling的ACTION_DOWN和最后一个ACTION_MOVE中包含的坐标等信息外,我们还可以根据用户在X轴或者Y轴上的移动速度作为条件。比如下面的代码中我们就在用户移动超过100个像素,且X轴上每秒的移动速度大于200像素时才进行处理。

    复制代码
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        // 参数解释:
        // 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(this, "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(this, "Fling Right", Toast.LENGTH_SHORT).show();
        }
        return false;
    }
    复制代码

    这个例子中,tv.setLongClickable(true)是必须的,因为只有这样,view才能够处理不同于Tap(轻触)的hold(即ACTION_MOVE,或者多个ACTION_DOWN),我们同样可以通过layout定义中的android:longClickable来做到这一点。

     4. SimpleOnGestureListener

    复制代码
    public class MyGesture extends Activity implements OnTouchListener {
        private GestureDetector mGestureDetector;
        public MyGesture() {
            mGestureDetector = new GestureDetector(new MySimpleGesture());
        }
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            TextView tv = (TextView) findViewById(R.id.tv);
            tv.setOnTouchListener(this);
            tv.setFocusable(true);
            tv.setClickable(true);
            tv.setLongClickable(true);
        }
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                Log.i("MyGesture", "MotionEvent.ACTION_UP");
            }
            return mGestureDetector.onTouchEvent(event);
        }
        
        // SimpleOnGestureListener implements GestureDetector.OnDoubleTapListener, GestureDetector.OnGestureListenerprivate 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 下的类似Windows下Everything的搜索工具
    windows和linux环境下制作U盘启动盘
    程序调试手段之gdb, vxworks shell
    LeetCode 1021. Remove Outermost Parentheses (删除最外层的括号)
    LeetCode 1047. Remove All Adjacent Duplicates In String (删除字符串中的所有相邻重复项)
    LeetCode 844. Backspace String Compare (比较含退格的字符串)
    LeetCode 860. Lemonade Change (柠檬水找零)
    LeetCode 1221. Split a String in Balanced Strings (分割平衡字符串)
    LeetCode 1046. Last Stone Weight (最后一块石头的重量 )
    LeetCode 746. Min Cost Climbing Stairs (使用最小花费爬楼梯)
  • 原文地址:https://www.cnblogs.com/jeffen/p/6877334.html
Copyright © 2011-2022 走看看