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

前端 未结 2 1137
情歌与酒
情歌与酒 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: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);
      

提交回复
热议问题