【问题标题】:How to implement a two-finger double-click in Android?如何在Android中实现两指双击?
【发布时间】:2012-09-07 00:54:36
【问题描述】:

我知道如何检测双击和两指触摸事件,但我如何将它们结合起来做出反应,以便有人需要用两根手指双击?

默认情况下,Android 有长按作为第二种点击形式,但我特意寻找双指双击。

【问题讨论】:

    标签: android multi-touch gesture double-click


    【解决方案1】:

    我想要一个简单且可重复使用的界面,它可以监听两个手指的双击,并且其行为类似于 GestureDetector。这样您就可以像这样使用它(所有剪切和粘贴可运行代码):

    public class Example extends Activity {
        SimpleTwoFingerDoubleTapDetector multiTouchListener = new SimpleTwoFingerDoubleTapDetector() {
            @Override
            public void onTwoFingerDoubleTap() {
                // Do what you want here, I used a Toast for demonstration
                Toast.makeText(Example.this, "Two Finger Double Tap", Toast.LENGTH_SHORT).show();
            }
        };
    
        // Override onCreate() and anything else you want
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if(multiTouchListener.onTouchEvent(event))
                return true;
            return super.onTouchEvent(event);
        }
    }
    

    我创建了 SimpleTwoFingerDoubleTapDetector。 (这是一个长名称,但它是描述性的。您可以将其重命名为您想要的任何名称。)将这个新文件保存在您的项目中或作为库:

    public abstract class SimpleTwoFingerDoubleTapDetector {
        private static final int TIMEOUT = ViewConfiguration.getDoubleTapTimeout() + 100;
        private long mFirstDownTime = 0;
        private boolean mSeparateTouches = false;
        private byte mTwoFingerTapCount = 0;
    
        private void reset(long time) {
            mFirstDownTime = time;
            mSeparateTouches = false;
            mTwoFingerTapCount = 0;
        }
    
        public boolean onTouchEvent(MotionEvent event) {
            switch(event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                if(mFirstDownTime == 0 || event.getEventTime() - mFirstDownTime > TIMEOUT) 
                    reset(event.getDownTime());
                break;
            case MotionEvent.ACTION_POINTER_UP:
                if(event.getPointerCount() == 2)  
                    mTwoFingerTapCount++;
                else 
                    mFirstDownTime = 0;
                break;
            case MotionEvent.ACTION_UP:
                if(!mSeparateTouches)
                    mSeparateTouches = true;
                else if(mTwoFingerTapCount == 2 && event.getEventTime() - mFirstDownTime < TIMEOUT) {
                    onTwoFingerDoubleTap();
                    mFirstDownTime = 0;
                    return true;
                }
            }               
    
            return false;
        }
    
        public abstract void onTwoFingerDoubleTap();
    }
    

    首先,关于 Android(一键式)GestureDetector的一些注意事项:

    • Android 的onDoubleTap() 事件使用来自 ViewConfiguration 的标准超时值。我指的是同一时间。
    • 他们测量从第一次点击的手指向下事件到第二次点击的手指向下事件的经过时间,然后广播onDoubleTap()onDoubleTapEvent()
      • onDoubleTap() 仅在第二次点击的手指向下事件发生时触发。
      • onDoubleTapEvent() 在第二次点击时触发每个动作:向下、移动和向上。

    关于SimpleTwoFingerDoubleTapDetector的几点说明:

    • 我的超时时间是从第一个手指向下事件到最后一个手指向上 事件,以防止错误的双击通知。我为默认的 ViewConfiguration 双击超时添加了一点额外时间来解决这个问题。
    • Android 的 GestureDetector 测量倾斜度(两次点击的距离)。我没有看到这里需要这样做,也没有检查每次点击时两个手指之间的距离。
    • 我只广播了一个事件onTwoFingerDoubleTap()

    最后说明: 您可以轻松将其更改为类似于 OnTouchListener:

    1. 更改 SimpleTwoFingerDoubleTapDetector 的定义:

      public abstract class SimpleTwoFingerDoubleTapListener implements OnTouchListener {
      
    2. 添加一个新的类变量:

      private View mFirstView;
      
    3. 更改ACTION_DOWN 大小写:

      case MotionEvent.ACTION_DOWN:
          if(mFirstDownTime == -1 || mFirstView != v || hasTimedOut(event.getEventTime())) {
              mFirstView = v;
              reset(event.getDownTime());
          }
          break;
      
    4. ACTION_UP 案例中传递mFirstView

      onTwoFingerDoubleTap(mFirstView);
      
    5. 最后,更改onTwoFingerDoubleTap() 方法以反映哪个视图被点击:

      public abstract void onTwoFingerDoubleTap(View v);
      

    【讨论】:

    • 这个答案太棒了!
    • 我已经尝试过这段代码(谢谢!)但它不起作用 - 我只收到 ACTION_DOWN 事件。我相信 onTouchEvent() 函数必须返回 True(对于 ACTION_DOWN),否则之后将不会收到 ACTION_UP。参考:stackoverflow.com/a/16495363/1277048
    • 谢谢,尽管它不起作用。它帮助我找到正确的答案。
    【解决方案2】:

    这是我为检测两指双击而创建的双击监听器。

    使用的变量:

    private GestureDetector gesture;
    private View.OnTouchListener gestureListener;
    boolean click1 = false;
    boolean click2 = false;
    long first = 0;
    long second = 0;
    

    在activity的onCreate()注册触摸事件:

    gesture = new GestureDetector(getApplicationContext(), new SimpleOnGestureListener(){
        public boolean onDown(MotionEvent event) {
            return true;
        }
    });
    gestureListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return gesture.onTouchEvent(event);
        }
    };
    

    onCreate() 外的活动内:

    @Override
    public boolean onTouchEvent(MotionEvent event) {   
        try {
            int action = event.getAction() & MotionEvent.ACTION_MASK;
            //capture the event when the user lifts their fingers, not on the down press
            //to make sure they're not long pressing
            if (action == MotionEvent.ACTION_POINTER_UP) {
                //timer to get difference between clicks
                Calendar now = Calendar.getInstance();
    
                //detect number of fingers, change to 1 for a single-finger double-click, 3 for a triple-finger double-click, etc.
                if (event.getPointerCount() == 2) {
                    if (!click1) {
                        //if this is the first click, then there hasn't been a second
                        //click yet, also record the time
                        click1 = true;
                        click2 = false;
                        first = now.getTimeInMillis(); 
                    } else if (click1) {
                        //if this is the second click, record its time 
                        click2 = true;
                        second = now.getTimeInMillis();
    
                        //if the difference between the 2 clicks is less than 500 ms (1/2 second)
                        //Math.abs() is used because you need to be able to detect any sequence of clicks, rather than just in pairs of two
                        //(e.g. click1 could be registered as a second click if the difference between click1 and click2 > 500 but
                        //click2 and the next click1 is < 500)
                        if (Math.abs(second-first) < 500) {
    
                            //do something!!!!!!
    
                        } else if (Math.abs(second-first) >= 500) {
                            //reset to handle more clicks
                            click1 = false;
                            click2 = false;
                        }
                    }
                }
            }
        } catch (Exception e){
    
        }
        return true;
    }
    

    【讨论】:

    • if (click1 &amp;&amp; click2 &amp;&amp; Math.abs(second-first) &lt; 500) {...} 太过分了。除非click1 &amp;&amp; click2 已经为真,否则您无法访问代码的这个特定部分。要到达这里,您必须通过:if (click1) { click2 = true; ... }。使用if (Math.abs(second-first) &lt; 500) { //do something!!!!!! } else {click1 = false; click2 = false;}也可以达到同样的效果
    • @Nezam 我已经好几年没用过这段代码了,但我不知道为什么会这样——它在我们的应用中运行得很好
    猜你喜欢
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多