Search code examples
androidontouchlistenergesturedetector

differenciate Swipe and tap getsures android


I'm trying to make note app and have some problems : I have custom Edittext inside custom LinearLayout and trying to handle swipe on Edittext. I'm using this solution of swipe recognition OnSwipeTouchListener and it works perfect, until I tap on edittext (in witch case edittext doesn't get focus). I set OnSwipeTouchListener as edittext.ontouchlistener public class OnSwipeTouchListener implements View.OnTouchListener {

private GestureDetector gestureDetector;

public OnSwipeTouchListener(Context c) {
    gestureDetector = new GestureDetector(c, new GestureListener());
}

public boolean onTouch(final View view, final MotionEvent motionEvent) {
    return gestureDetector.onTouchEvent(motionEvent);

}

private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;


    @Override
    public boolean onSingleTapConfirmed(MotionEvent e){
        print(211212, "singleTap shemovida");
        return false;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    // Determines the fling velocity and then fires the appropriate swipe event accordingly
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        print(21512512, "fling");
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        onSwipeRight();
                    } else {
                        onSwipeLeft();
                    }
                }
            } else {
                if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        onSwipeDown();
                    } else {
                        onSwipeUp();
                    }
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}

static void print(int line, String st){
    PRINT.print("ONSwipeTouchListener", line, st);
}

public void onSwipeRight() {
}

public void onSwipeLeft() {
}

public void onSwipeUp() {
}

public void onSwipeDown() {
}

and I set it to edittext

    void addTextView(){
    _myText = new CustomEditText(getContext());
    LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    _myText.setLayoutParams(params);
    _myText.setId(getEditTextId());
    addView(_myText);
    _myText.setOnTouchListener(new OnSwipeTouchListener(getContext()) {
        @Override
        public void onSwipeDown() {

        }

        @Override
        public void onSwipeLeft() {
            CustomEditTextWithCheckbox.this.onSwipeLeft();
        }

        @Override
        public void onSwipeUp() {
        }

        @Override
        public void onSwipeRight() {
            CustomEditTextWithCheckbox.this.onSwipeRight();
        }
    });
}

but as I guess in OnSwipeTouchListener.OnTouch always returns true and so edittext does not get focus. I have also tryed to change onTouch

 public boolean onTouch(final View view, final MotionEvent motionEvent) {
   gestureDetector.onTouchEvent(motionEvent);
    return false;
}

and it works, but still problem is that on swipe edittext gets focus when i want to swipe, And I understand why its working like that. But i need that if user does not swipe than on touch should return false, else true. Can anyone help


Solution

  • I found a good solution for my question here u need to change a bit SwipeDismissTouchListener this way

    public class SwipeDismissTouchListener implements View.OnTouchListener {
    
    private int mSlop;
    private int mMinFlingVelocity;
    private int mMaxFlingVelocity;
    private long mAnimationTime;
    
    // Fixed properties
    private CustomEditTextWithCheckbox mView;
    private DismissCallbacks mCallbacks;
    private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
    
    // Transient properties
    private float mDownX;
    private float mDownY;
    private boolean mSwiping;
    private int mSwipingSlop;
    private VelocityTracker mVelocityTracker;
    private float mTranslationX;
    
    public interface DismissCallbacks {
        boolean canDismiss();
        void onDismiss(View view);
    }
    
    public SwipeDismissTouchListener(CustomEditTextWithCheckbox view, DismissCallbacks callbacks) {
        ViewConfiguration vc = ViewConfiguration.get(view.getContext());
        mSlop = vc.getScaledTouchSlop();
        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
        mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
        mAnimationTime = view.getContext().getResources().getInteger(
                android.R.integer.config_shortAnimTime);
        mView = view;
        mCallbacks = callbacks;
    }
    
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        // offset because the view is translated during swipe
        motionEvent.offsetLocation(mTranslationX, 0);
    
        if (mViewWidth < 2) {
            mViewWidth = mView.getWidth();
        }
    
        switch (motionEvent.getActionMasked()) {
            case MotionEvent.ACTION_DOWN: {
                // TODO: ensure this is a finger, and set a flag
                mDownX = motionEvent.getRawX();
                mDownY = motionEvent.getRawY();
                if (mCallbacks.canDismiss()) {
                    mVelocityTracker = VelocityTracker.obtain();
                    mVelocityTracker.addMovement(motionEvent);
                }
                return false;
            }
    
            case MotionEvent.ACTION_UP: {
                if (mVelocityTracker == null) {
                    break;
                }
    
                float deltaX = motionEvent.getRawX() - mDownX;
                mVelocityTracker.addMovement(motionEvent);
                mVelocityTracker.computeCurrentVelocity(1000);
                float velocityX = mVelocityTracker.getXVelocity();
                float absVelocityX = Math.abs(velocityX);
                float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
                boolean dismissRight = false;
                if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
                    dismissRight = deltaX > 0;
                } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
                        && absVelocityY < absVelocityX
                        && absVelocityY < absVelocityX && mSwiping) {
                    dismissRight = mVelocityTracker.getXVelocity() > 0;
                }
                if (dismissRight) {
                   mView.onSwipeRight();
                } else if (mSwiping) {
                   mView.onSwipeLeft();
                }
                mVelocityTracker.recycle();
                mVelocityTracker = null;
                mTranslationX = 0;
                mDownX = 0;
                mDownY = 0;
                mSwiping = false;
                break;
            }
    
            case MotionEvent.ACTION_CANCEL: {
                if (mVelocityTracker == null) {
                    break;
                }
    
                mVelocityTracker.recycle();
                mVelocityTracker = null;
                mTranslationX = 0;
                mDownX = 0;
                mDownY = 0;
                mSwiping = false;
                break;
            }
    
            case MotionEvent.ACTION_MOVE: {
                if (mVelocityTracker == null) {
                    break;
                }
    
                mVelocityTracker.addMovement(motionEvent);
                float deltaX = motionEvent.getRawX() - mDownX;
                float deltaY = motionEvent.getRawY() - mDownY;
                if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
                    mSwiping = true;
                    mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
                    mView.getParent().requestDisallowInterceptTouchEvent(true);
    
                    MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                            (motionEvent.getActionIndex() <<
                                    MotionEvent.ACTION_POINTER_INDEX_SHIFT));
                    mView.onTouchEvent(cancelEvent);
                    cancelEvent.recycle();
                }
    
                break;
            }
        }
        return false;
    }
    }
    

    doint this way it works perfectly, hope it will be helpfull