How to implement a two-finger double-click in Android?

前端 未结 2 1138
情歌与酒
情歌与酒 2020-12-30 13:37

I know how to detect a double-click and a two-finger touch event, but how can I combine these to react so somebody needs to double click with two fingers?

By default

相关标签:
2条回答
  • 2020-12-30 14:03

    This is a double-click listener I created to detect a two-finger double click.

    Variables used:

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

    In the activity's onCreate() to register the touch events:

    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);
        }
    };
    

    Outside of onCreate() inside the activity:

    @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;
    }
    
    0 讨论(0)
  • 2020-12-30 14:06

    I wanted a simple and reusable interface that listens for two finger double taps and behaves like GestureDetector. So that you could use it like this (all cut & paste runnable code):

    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);
        }
    }
    

    I created SimpleTwoFingerDoubleTapDetector. (It's a long name, but it is descriptive. You can rename it as anything you want.) Save this new file inside your project or as a library:

    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();
    }
    

    First, a few notes about Android (one-touch) GestureDetector:

    • Android's onDoubleTap() event uses a standard timeout value from ViewConfiguration. I refer to the same time.
    • They measure the elapsed time from the first tap's finger-down event to the second tap's finger-down event, and then broadcast onDoubleTap() and onDoubleTapEvent().
      • onDoubleTap() is fired only when the second tap's finger-down event occurs.
      • onDoubleTapEvent() is fired for every action by the second tap: down, move, and up.

    A few notes on SimpleTwoFingerDoubleTapDetector:

    • My timeout is measured from the first finger-down event to the last finger-up event to prevent false double-tap notifications. I added a little extra time to the default ViewConfiguration double tap timeout to account for this.
    • Android's GestureDetector measures slop (how far apart the two taps are). I didn't see the need for this here, nor did I check the distance between the two fingers on each tap.
    • I only broadcast one event onTwoFingerDoubleTap().

    Final note: You can easily change this to behave like an OnTouchListener:

    1. Change SimpleTwoFingerDoubleTapDetector's definition:

      public abstract class SimpleTwoFingerDoubleTapListener implements OnTouchListener {
      
    2. Add a new class variable:

      private View mFirstView;
      
    3. Change the ACTION_DOWN case:

      case MotionEvent.ACTION_DOWN:
          if(mFirstDownTime == -1 || mFirstView != v || hasTimedOut(event.getEventTime())) {
              mFirstView = v;
              reset(event.getDownTime());
          }
          break;
      
    4. Pass mFirstView inside the ACTION_UP case:

      onTwoFingerDoubleTap(mFirstView);
      
    5. Last, change the onTwoFingerDoubleTap() method to reflect which View was tapped:

      public abstract void onTwoFingerDoubleTap(View v);
      
    0 讨论(0)
提交回复
热议问题