How to make swipe with recycler view item?

1.1k views Asked by At

I am working on floating Keyboard using Recycler view which would appear on screen when a button is clicked and dismisses when Right / Left swipe is done. As I am doing so I observed the swiping the keyboard is not smoother (Some times swipe listeners does not detect swipe gestures.) . Then I referred the following links and re-worked,

https://medium.com/@euryperez/android-pearls-detect-swipe-and-touch-over-a-view-203ae2c028dc

https://stackoverflow.com/questions/4139288/android-how-to-handle-right-to-left-swipe-gestures.

I added gesture listeners to the child of Recycler view and used three override methods onClick(), onSwipeRight() and onSwipeLeft(). The position of the onClick is obtained perfectly but sometimes Swipe Listeners are not detected this makes users to feel swiping is not smoother.

All I needed is to make swipe smoother and detecting position of clicking keys without compromising both. Is there any ways to implement these feature if there any way suggest me!. Here is my code. Thanks in Advance !.

public ViewHolder(View v) {
 super(v);
 textView = (TextView) v.findViewById(R.id.textView);
 imageView = (ImageView) v.findViewById(R.id.imageView);
 relativeLayout = (RelativeLayout) v.findViewById(R.id.relativeLayout);
 mBodyContainer = (ConstraintLayout) v.findViewById(R.id.body_container);
 cllayout = (RelativeLayout) v.findViewById(R.id.cllayout);
 setSwipeGestureForParent(cllayout);
 }

  private void setSwipeGestureForParent(final View view) {
  view.setOnTouchListener(new OnSwipeTouchListener(mContext) {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
  parentview.stopScroll();
  String view = item.text;
  if (view.equals("")) {
  } else if (v.getId() != R.id.body_container && !view.equals("")) {
  switch (event.getAction()) 
  {
  case MotionEvent.ACTION_DOWN:
  imageView.setBackground(ContextCompat.getDrawable(mContext,             R.drawable.bg_keyboard_key_selected));
  break;
  case MotionEvent.ACTION_MOVE:
  imageView.setBackground(ContextCompat.getDrawable(mContext,     R.drawable.bg_keyboard_key_selected));
  break;
  case MotionEvent.ACTION_BUTTON_PRESS:
  imageView.setBackground(ContextCompat.getDrawable(mContext,       R.drawable.bg_keyboard_key_selected));
  break;
  default:
  imageView.setBackground(ContextCompat.getDrawable(mContext,   R.drawable.bg_keyboard_key_normal));
  break;
  }
  }
  return super.onTouch(v, event);
  }

  @Override
  public void onClick() {
  super.onClick();
  Toast.makeText(mContext, "onclick", Toast.LENGTH_SHORT).show();
  }

  @Override
  public void onSwipeLeft() {
  Toast.makeText(mContext, "Swipeleft", Toast.LENGTH_SHORT).show();
  }

  @Override
  public void onSwipeRight() {
  Toast.makeText(mContext, "SwipeRight", Toast.LENGTH_SHORT).show();
  }
  });
  }
1

There are 1 answers

0
tm1701 On

I have prepared 2 general 'copy-and-paste' classes for you so you can very easily use all gestures on the RecyclerView.

1 - GestureDetector - just add it to your project

class OnSwipeTouchListener implements View.OnTouchListener {
    private final GestureDetector gestureDetector;
    public OnSwipeTouchListener(Context ctx, TouchListener touchListener) {
        gestureDetector = new GestureDetector(ctx, new GestureListener(touchListener));
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }
    private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
        private static final int SWIPE_THRESHOLD = 300;
        private static final int SWIPE_VELOCITY_THRESHOLD = 300;
        private TouchListener touchListener;
        GestureListener(TouchListener touchListener) {
            super();
            this.touchListener = touchListener;
        }
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.i("TAG", "onSingleTapConfirmed:");
            touchListener.onSingleTap();
            return true;
        }
        @Override
        public void onLongPress(MotionEvent e) {
            Log.i("TAG", "onLongPress:");
            touchListener.onLongPress();
        }
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            touchListener.onDoubleTap();
            return true;
        }
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            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) {
                            touchListener.onSwipeRight();
                        } else {
                            touchListener.onSwipeLeft();
                        }
                        result = true;
                    }
                } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        touchListener.onSwipeDown();
                    } else {
                        touchListener.onSwipeUp();
                    }
                    result = true;
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }
}

2 - TouchListener - just add the interface definition to your project. To make the use even more easy, I have used some default implementations of the interface. So, you need to add to your module's build.gradle:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

Add the interface:

public interface TouchListener  {
    void onSingleTap();
    default void onDoubleTap() {
        Log.i("TAG",  "Double tap");
    }
    default void onLongPress() {
        Log.i("TAG", "Long press");
    }
    default void onSwipeLeft() {
        Log.i("TAG", "Swipe left");
    }
    default void onSwipeRight() {
        Log.i("TAG", "Swipe right");
    }
    default void onSwipeUp() {
        Log.i("TAG", "Swipe up");
    }
    default void onSwipeDown() {
        Log.i("TAG", "Swipe down");
    }
}

3 - Now you can attach to any view the TouchListener and implement only those methods you really need. An example is:

holder.anyview.setOnTouchListener(new OnSwipeTouchListener(mCtx, new TouchListener() {
            @Override
            public void onSingleTap() {
                Log.i("TAG", ">> Single tap");
            }

            @Override
            public void onDoubleTap() {
                Log.i("TAG", ">> Double tap");
            }

            @Override
            public void onLongPress() {
                Log.i("TAG", ">> "Long press");
            }

            @Override
            public void onSwipeLeft() {
                Log.i("TAG", ">> Swipe left");
            }

            @Override
            public void onSwipeRight() {
                Log.i("TAG", ">> Swipe right");

            }
        }));

That's all! Enjoy.