Skip to content

Instantly share code, notes, and snippets.

@NikolaDespotoski
Created January 22, 2017 20:51
Show Gist options
  • Save NikolaDespotoski/b828f77e4b58c6d89583a49083abea24 to your computer and use it in GitHub Desktop.
Save NikolaDespotoski/b828f77e4b58c6d89583a49083abea24 to your computer and use it in GitHub Desktop.
public class DragSelectionItemTouchListener extends LongPressItemTouchListener implements RecyclerView.OnItemTouchListener {
private RecyclerView.ViewHolder mPreviousViewHolder;
private Rect mHitRect = new Rect();
private List<RecyclerView.ViewHolder> mRangeSelection = new ArrayList<>();
public DragSelectionItemTouchListener(Context context, OnItemInteractionListener listener) {
super(context, listener);
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_POINTER_UP) {
cancelPreviousSelection();
return false;
} else {
onLongPressedEvent(rv, e);
}
return mViewHolderLongPressed != null;
}
private void cancelPreviousSelection() {
mViewHolderLongPressed = null;
mViewHolderInFocus = null;
mPreviousViewHolder = null;
mRangeSelection.clear();
}
private boolean onActionMove(RecyclerView rv, MotionEvent e) {
if (isMotionEventInCurrentViewHolder(e) || mViewHolderLongPressed == null) {
return false;
}
if (mViewHolderLongPressed != null && mPreviousViewHolder == null) {
mPreviousViewHolder = mViewHolderLongPressed;
}
View childViewUnder = rv.findChildViewUnder(e.getX(), e.getY());
if (childViewUnder == null) return false;
RecyclerView.ViewHolder viewHolder = rv.getChildViewHolder(childViewUnder);
if (mPreviousViewHolder == null && viewHolder != null && mViewHolderLongPressed != null && viewHolder.getAdapterPosition() != mViewHolderLongPressed.getAdapterPosition()) {
dispatchOnViewHolderHovered(rv, viewHolder);
return true;
} else if (mPreviousViewHolder != null && viewHolder != null && viewHolder.getAdapterPosition() != mPreviousViewHolder.getAdapterPosition()) {
dispatchOnViewHolderHovered(rv, viewHolder);
return true;
}
return false;
}
private boolean isMotionEventInCurrentViewHolder(MotionEvent e) {
if (mPreviousViewHolder != null) {
mPreviousViewHolder.itemView.getHitRect(mHitRect);
return mHitRect.contains((int) e.getX(), (int) e.getY());
}
return false;
}
private void dispatchOnViewHolderHovered(RecyclerView rv, RecyclerView.ViewHolder viewHolder) {
if (!checkForSpanSelection(rv, viewHolder)) {
if (mListener != null) {
mListener.onViewHolderHovered(rv, viewHolder);
}
}
mPreviousViewHolder = viewHolder;
}
private boolean checkForSpanSelection(RecyclerView rv, RecyclerView.ViewHolder viewHolder) {
if (rv.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager.LayoutParams endSelectionParams = (GridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
GridLayoutManager.LayoutParams startSelectionParams = (GridLayoutManager.LayoutParams) mPreviousViewHolder.itemView.getLayoutParams();
if (endSelectionParams.getSpanIndex() != startSelectionParams.getSpanIndex()) {
dispatchRangeSelection(rv, viewHolder);
return true;
}
}
return false;
}
private void dispatchRangeSelection(RecyclerView rv, RecyclerView.ViewHolder viewHolder) {
if (mListener != null) {
mRangeSelection.clear();
int start = Math.min(mPreviousViewHolder.getAdapterPosition() + 1, viewHolder.getAdapterPosition());
int end = Math.max(mPreviousViewHolder.getAdapterPosition() + 1, viewHolder.getAdapterPosition());
for (int i = start; i <= end; i++) {
mRangeSelection.add(rv.findViewHolderForAdapterPosition(i));
}
mListener.onMultipleViewHoldersSelected(rv, mRangeSelection);
}
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_POINTER_UP) {
cancelPreviousSelection();
} else if (mViewHolderLongPressed != null) {
onActionMove(rv, e);
}
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
public abstract class LongPressItemTouchListener extends RecyclerView.SimpleOnItemTouchListener {
private final GestureDetector mGestureDetector;
protected final OnItemInteractionListener mListener;
protected RecyclerView.ViewHolder mViewHolderLongPressed;
public RecyclerView.ViewHolder mViewHolderInFocus;
public LongPressItemTouchListener(Context context, OnItemInteractionListener listener) {
mGestureDetector = new GestureDetector(context, new LongPressGestureListener());
mGestureDetector.setIsLongpressEnabled(true);
mListener = listener;
}
public boolean onLongPressedEvent(RecyclerView rv, MotionEvent e) {
if (mViewHolderLongPressed != null) {
return false;
// long pressed happened, my job here is done.
}
View childViewUnder = rv.findChildViewUnder(e.getX(), e.getY());
if (childViewUnder != null) {
mViewHolderInFocus = rv.findContainingViewHolder(childViewUnder);
if (mGestureDetector.onTouchEvent(e) && mListener != null) {
mListener.onItemClicked(rv, mViewHolderInFocus, rv.getChildAdapterPosition(childViewUnder));
}
return mViewHolderLongPressed != null;
}
return false;
}
class LongPressGestureListener extends SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
if (mViewHolderInFocus != null && mListener != null) {
RecyclerView recyclerView = (RecyclerView) mViewHolderInFocus.itemView.getParent();
mListener.onLongItemClicked(recyclerView, mViewHolderInFocus, mViewHolderInFocus.getAdapterPosition());
mViewHolderLongPressed = mViewHolderInFocus;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment