75

I am trying to implement swipe to delete the same as Gmail app "Swipe to archive":

gmail swipe delete gmail swipe delete

I have tried many tutorials but none of them works as fast as gmail, I prefer to not work on external library. How can i do it?

Edit:

My code so far-

  ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
                public boolean onMove(RecyclerView recyclerView,
                                               RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//                    final int fromPos = viewHolder.getAdapterPosition();
//                    final int toPos = viewHolder.getAdapterPosition();
//                    // move item in `fromPos` to `toPos` in adapter.
                    return true;// true if moved, false otherwise
                }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
                //Remove swiped item from list and notify the RecyclerView
                mAdapter.notifyItemRemoved(viewHolder.getLayoutPosition());
            }
        };
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
        itemTouchHelper.attachToRecyclerView(mRecyclerView);

I've managed to enable swipe gesture but i don't know how to add a background and an image under the viewHolder. I tried to put another FrameLayout at the item_XXX.xml file but on swipe it throws the whole item with the background.

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
Montoya
  • 2,819
  • 3
  • 37
  • 65
  • 1
    This will help:- http://stackoverflow.com/questions/27293960/swipe-to-dismiss-for-recyclerview – Paresh P. Nov 29 '15 at 17:32
  • Have a look http://stackoverflow.com/questions/30820806/adding-a-colored-background-with-text-icon-under-swiped-row-when-using-androids, there is a solution using overriding onChildDraw. – Pierre R-A Dec 18 '15 at 17:58
  • am looking for longpresson item populate contextual action mode with delete option android please help me – Harsha Oct 15 '16 at 08:44
  • how can i implement like gmail single and multiselection with cab popup for menu items remove share – Harsha Oct 15 '16 at 09:08
  • 1
    I strongly recommended to look at this tutorial: https://medium.com/@kitek/recyclerview-swipe-to-delete-easier-than-you-thought-cff67ff5e5f6 – mamakurka Nov 26 '18 at 14:32
  • 1
    See https://www.androidhive.info/2017/09/android-recyclerview-swipe-delete-undo-using-itemtouchhelper/. – CoolMind Jul 30 '19 at 15:38

4 Answers4

72

Simple Code for RecyclerView Swipe:

     ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.DOWN | ItemTouchHelper.UP) {

            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                Toast.makeText(ListActivity.this, "on Move", Toast.LENGTH_SHORT).show();
                return false;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
                Toast.makeText(ListActivity.this, "on Swiped ", Toast.LENGTH_SHORT).show();
                //Remove swiped item from list and notify the RecyclerView
                int position = viewHolder.getAdapterPosition();
                arrayList.remove(position);
                adapter.notifyDataSetChanged();

            }
     };

Then set callback for recyclerView with below statements:

ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
 itemTouchHelper.attachToRecyclerView(rv);
Rahul Raina
  • 3,322
  • 25
  • 30
  • 11
    For a smother animation you can use 'adapter.notifyItemRemoved(position)' instead of 'adapter.notifyDataSetChanged();' – LMiranda Aug 05 '20 at 21:26
  • @LMiranda Im having a problem with notifyItemRemoved(position): when I call it, the item that I swiped is removed, however another element is drawn in the list, and inside the adaptar the size of the list hasn't actually changed, even though I did remove the element. In example, if I have 3 elements and I remove one, the getItemCount in the adapter still returns 3 and then redraws one of the items again, any clue as to why it's happening? – FabioR Aug 26 '20 at 16:19
  • you'll need to remove the item from list inside the adapter also. remove the item from list then use adapter.notifyItemRemoved(position) and 'adapter.notifyDataSetChanged() to make it work – Sanket Patel Sep 04 '20 at 05:51
32

I had to do this the other day and I had some issues so I decided to write a blog post on it. No 3rd party lib necessary.

Basically, you wouldn't draw the "undo state" via onChildDraw, it would be done via ViewHolder. Also you wouldn't actually delete row in onSwipe just mark it as "pending delete" and notify adapter to rebind it in "undo state". At the same time you post a Runnable actually removing the row in x seconds unless undo button is pressed...

Nemanja Kovacevic
  • 3,510
  • 2
  • 30
  • 45
  • Nice implementation even I was trying something similar to that I was able to achieve swipe in both the directions [Partial Swipe](http://stackoverflow.com/questions/34747458/partial-and-full-swipe-for-recyclerview-using-touchhelpercallback) but can we achieve a partial swipe, just to let user know they can do the same operation with partial swipe ? – Srikanth Roopa Jan 12 '16 at 18:13
  • Is it possible to do this onclick instead of onswipe? – gdubs Aug 17 '16 at 18:25
  • gmail single and multiselection recyclerview longpress contextual action mode popup for delete ad share – Harsha Oct 15 '16 at 08:48
  • I have implemented your code, how Do I add onClickListener to `delete` icon – rookieDeveloper Nov 04 '16 at 11:57
  • @rookieDeveloper try this !! https://github.com/ashrithks/SwipeRecyclerView , u can customize the view on swiped. – Ashrith K S Dec 09 '16 at 08:49
  • You can get help form this tutorial http://www.sunilandroid.com/2016/12/swipe-to-delete-item-of-recyclerview-in.html – Sunil Kumar Mar 02 '17 at 06:22
  • I cannot seem to view your blog post anymore @nemanja . Did you remove it? – kjanderson2 Mar 10 '17 at 18:01
  • 1
    Hi @kjanderson2 it should be accessible again, I had some issues with the website... – Nemanja Kovacevic Mar 12 '17 at 18:48
8

Here's the minimum code in your onCreate that sets up "Swipe Left to Delete":

binding.rows.adapter = adapter
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
    override fun onMove(v: RecyclerView, h: RecyclerView.ViewHolder, t: RecyclerView.ViewHolder) = false
    override fun onSwiped(h: RecyclerView.ViewHolder, dir: Int) = adapter.removeAt(h.adapterPosition)
}).attachToRecyclerView(binding.rows)

This assumes your Adapter class has a removeAt function. Mine looks like this:

fun removeAt(index: Int) {
    items.removeAt(index)   // items is a MutableList
    notifyItemRemoved(index)
}

Thanks @RahulRaina for your Java answer!

AmrDeveloper
  • 3,826
  • 1
  • 21
  • 30
JohnnyLambada
  • 12,700
  • 11
  • 57
  • 61
2

You can try Swipeable-RecyclerView

    SwipeableRecyclerView rv = findViewById(R.id.rv);
    rv.setLayoutManager(new LinearLayoutManager(this));
    rv.setAdapter(mAdapter);

    rv.setListener(new SwipeLeftRightCallback.Listener() {
        @Override
        public void onSwipedLeft(int position) {
            mList.remove(position);
            mAdapter.notifyDataSetChanged();
        }

        @Override
        public void onSwipedRight(int position) {
            mList.remove(position);
            mAdapter.notifyDataSetChanged();
        }
    });

xml for two sides swipe

<com.tsuryo.swipeablerv.SwipeableRecyclerView
    android:id="@+id/rv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:leftBgColor="@color/colorAccent"
    app:leftImage="@drawable/ic_remove"
    app:leftText="Delete"
    app:rightBgColor="@color/blue"
    app:rightImage="@drawable/ic_check"
    app:rightText="Read"
    app:textColor="@android:color/white"
    app:textSize="20sp" />