Join the social network of Tech Nerds, increase skill rank, get work, manage projects...
 
  • How to drag, drop and swipe in Android RecylerView?

    • 0
    • 0
    • 0
    • 0
    • 2
    • 0
    • 0
    • 0
    • 7.58k
    Comment on it

    Hello Friends,

    This tutorial will help you to implement "drag & drop" and "swipe" functionality  with Recyclerview items. There are many different ways to implement this features but we are using really a simple way to add these features in Recyclerview. It’s already part of the Android Support Library and needs one class. This class is called ItemTouchHelper.

    ItemTouchHelper :- ItemTouchHelper is a powerful class that can do everything you need to drag, drop, swipe in RecyclerView. It’s a subclass of RecyclerView.ItemDecoration, that mean it's easily added to existing LinearLayout Manager and Adapter.

    We can implement this feature by following steps.

    Step-1: First we’ll create an interface ItemTouchHelperAdapter that allows us to pass two events onMove() and onSwiped() event callbacks back up the chain.

    public interface ItemTouchHelperAdapter { 
    
     void onItemMove(int fromPosition, int toPosition);
     void onItemDismiss(int position);
     
    }

    This interface will implement by RecyclerViewAdapter class as listener

     

    Step-2: Defined here complete code for RecyclerView Adapter which implement ItemTouchHelperAdapter interface

    public class RecylerViewAdapter extends RecyclerView.Adapter<RecylerViewAdapter.ViewHolder>  implements ItemTouchHelperAdapter {
    
    
        private ArrayList<String> list;
        private final OnStartDragListener mDragStartListener;
    
    
        public RecylerViewAdapter(ArrayList<String> list, Context context, OnStartDragListener dragStartListener) {
    
            this.list = list;
            mDragStartListener = dragStartListener;
    
    
    
        }
    
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
            return new ViewHolder(v);
        }
    
        @Override
        public void onBindViewHolder(final ViewHolder holder, final int position) {
    
            holder.textView.setText(list.get(position));
            holder.imageView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
    
                    if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
                        mDragStartListener.onStartDrag(holder);
                    }
                    return false;
                }
            });
    
    
    
    
    
        }
    
        @Override
        public int getItemCount() {
            return list.size();
        }
    
        @Override
        public boolean onItemMove(int fromPosition, int toPosition) {
    
            Collections.swap(list, fromPosition, toPosition);
            notifyItemMoved(fromPosition, toPosition);
            return true;
        }
    
        @Override
        public void onItemDismiss(int position) {
    
            list.remove(position);
            notifyItemRemoved(position);
    
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder implements
                ItemTouchHelperViewHolder {
    
            TextView textView;
            ImageView imageView;
    
    
            public ViewHolder(View itemView) {
                super(itemView);
    
                textView=(TextView)itemView.findViewById(R.id.text);
                imageView=(ImageView)itemView.findViewById(R.id.handle);
    
    
    
            }
    
            @Override
            public void onItemSelected() {
    
                itemView.setBackgroundColor(Color.LTGRAY);
            }
    
            @Override
            public void onItemClear() {
    
                itemView.setBackgroundColor(0);
            }
        }
    
    
    
    }

    Here it is very necessary to call notifyItemRemoved() and notifyItemMoved() so that Adapter will get aware when any changes happen.

     

    Step-3: Defined another interface ItemTouchHelperViewHolder and implement by ViewHolder class.

    This interface holds two callbacks events. This callback call when you selected any item from RecyclerView.

    public interface ItemTouchHelperViewHolder {
    
     / * Implementations should update the item view to indicate it's active state. */ 
    void onItemSelected(); 
    
    /*
    Called when completed the move or swipe, and the active item * state should be cleared. 
    */ 
    
    void onItemClear();
    
     } 

     

    Step-4: Defined interface OnStartDragListener .

    **
     * Listener for manual initiation of a drag.
     */
    public interface OnStartDragListener {
    
        /**
         * Called when a view is requesting a start of a drag.
         */
        void onStartDrag(RecyclerView.ViewHolder viewHolder);
    
    }
    
    

     

    Finally, We will define resulting call back class SimpleItemTouchHelperCallback

    public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
    
        public static final float ALPHA_FULL = 1.0f;
    
        private final ItemTouchHelperAdapter mAdapter;
    
        public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
            mAdapter = adapter;
        }
    
        @Override
        public boolean isLongPressDragEnabled() {
            return true;
        }
    
        @Override
        public boolean isItemViewSwipeEnabled() {
            return true;
        }
    
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            // Set movement flags based on the layout manager
            if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
                final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                final int swipeFlags = 0;
                return makeMovementFlags(dragFlags, swipeFlags);
            } else {
                final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
                return makeMovementFlags(dragFlags, swipeFlags);
            }
        }
    
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
            if (source.getItemViewType() != target.getItemViewType()) {
                return false;
            }
    
            // Notify the adapter of the move
            mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
            return true;
        }
    
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
            // Notify the adapter of the dismissal
            mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
        }
    
        @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
                // Fade out the view as it is swiped out of the parent's bounds
                final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
                viewHolder.itemView.setAlpha(alpha);
                viewHolder.itemView.setTranslationX(dX);
            } else {
                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            }
        }
    
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            // We only want the active item to change
            if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
                if (viewHolder instanceof ItemTouchHelperViewHolder) {
                    // Let the view holder know that this item is being moved or dragged
                    ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
                    itemViewHolder.onItemSelected();
                }
            }
    
            super.onSelectedChanged(viewHolder, actionState);
        }
    
        @Override
        public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            super.clearView(recyclerView, viewHolder);
    
            viewHolder.itemView.setAlpha(ALPHA_FULL);
    
            if (viewHolder instanceof ItemTouchHelperViewHolder) {
                // Tell the view holder it's time to restore the idle state
                ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
                itemViewHolder.onItemClear();
            }
        }
    }

     

    Step-5 : With our Callback ready, we can create our ItemTouchHelper and call attachToRecyclerView(RecyclerView) in MainActivity class and implement interface onStartDragListener.

    ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); 
    
    ItemTouchHelper touchHelper = new ItemTouchHelper(callback); 
    
    touchHelper.attachToRecyclerView(recyclerView);
    @Override
    public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
      mItemTouchHelper.startDrag(viewHolder);
    }

     

    Step-6: Create a XML file for the items in RecyclerView item_layout.xml

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/item"
        android:layout_width="match_parent"
        android:layout_height="?listPreferredItemHeight"
        android:clickable="true"
        android:focusable="true"
        android:foreground="?selectableItemBackground">
    
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="@dimen/activity_horizontal_margin"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    
        <ImageView
            android:id="@+id/handle"
            android:layout_width="?listPreferredItemHeight"
            android:layout_height="match_parent"
            android:layout_gravity="center_vertical|right"
            android:scaleType="center"
            android:src="@drawable/ic_reorder_grey_500_24dp" />
    </FrameLayout>
    
    

 2 Comment(s)

Sign In
                           OR                           
                           OR                           
Register

Sign up using

                           OR                           
Forgot Password
Fill out the form below and instructions to reset your password will be emailed to you:
Reset Password
Fill out the form below and reset your password: