The ItemTouchHelper class added in Android Support Library V7 can be used to delete an item of RecyclerView by swiping the item with undo functionality. Or in other words, we can create a swipe to delete the items of RecyclerView, using the ItemTouchHelper class. To configure the events to be performed to swipe or move the item of the RecyclerView, the ItemTouchHelper class has a SimpleCallback class.
ItemTouchHelper class:
To swipe to dismiss and drag & drop the items of RecyclerView, the ItemTouchHelper class is used which is a utility class. Depending on the functionality to be implemented, the ItemTouchHelper class overrides the onMove() or onSwipe() callback methods.
Example:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:id="@+id/coordinatorLayout" android:layout_height="match_parent" tools:context=".MainActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> </RelativeLayout> </android.support.design.widget.CoordinatorLayout> |
cardview_row.xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:id="@+id/cardView" android:layout_width="match_parent" android:layout_height="64dp" android:layout_margin="8dp" card_view:cardCornerRadius="0dp" card_view:cardElevation="2dp"> <RelativeLayout android:id="@+id/relativeLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="8dp" android:paddingLeft="8dp" android:paddingRight="8dp"> <TextView android:id="@+id/txtTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:text="Item 1" android:textAppearance="@style/TextAppearance.Compat.Notification.Title" /> </RelativeLayout> </android.support.v7.widget.CardView> |
MainActivity.java:
In the MainActivity.java file, we will write the below code.
package com.example.radioapp; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { RecyclerView recyclerView; RecyclerViewAdapter mAdapter; ArrayList<String> stringArrayList = new ArrayList<>(); CoordinatorLayout coordinatorLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recyclerView); coordinatorLayout = findViewById(R.id.coordinatorLayout); populateRecyclerView(); enableSwipeToDeleteAndUndo(); } private void populateRecyclerView() { stringArrayList.add("Student 1"); stringArrayList.add("Student 2"); stringArrayList.add("Student 3"); stringArrayList.add("Student 4"); stringArrayList.add("Student 5"); stringArrayList.add("Student 6"); stringArrayList.add("Student 7"); stringArrayList.add("Student 8"); stringArrayList.add("Student 9"); stringArrayList.add("Student 10"); mAdapter = new RecyclerViewAdapter(stringArrayList); recyclerView.setAdapter(mAdapter); } private void enableSwipeToDeleteAndUndo() { SwipeToDeleteCallback swipeToDeleteCallback = new SwipeToDeleteCallback(this) { @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) { final int position = viewHolder.getAdapterPosition(); final String item = mAdapter.getData().get(position); mAdapter.removeItem(position); Snackbar snackbar = Snackbar .make(coordinatorLayout, "Item was removed from the list.", Snackbar.LENGTH_LONG); snackbar.setAction("UNDO", new View.OnClickListener() { @Override public void onClick(View view) { mAdapter.restoreItem(item, position); recyclerView.scrollToPosition(position); } }); snackbar.setActionTextColor(Color.YELLOW); snackbar.show(); } }; ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeToDeleteCallback); itemTouchhelper.attachToRecyclerView(recyclerView); } } |
SwipeToDeleteCallback.java:
In the SwipeToDeleteCallback.java file, we will extend the ItemTouchHelper.SimpleCallback class. We will also override its onMove(), onSwiped(), onChildDraw() methods. To perform the swipe operation on an item, we will call the onSwiped() method. To include the implementation logic of drawing canvas while swiping the items of RecyclerView, the onChildDraw() methods are called.
package com.example.radioapp; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; abstract public class SwipeToDeleteCallback extends ItemTouchHelper.Callback { Context mContext; private Paint mClearPaint; private ColorDrawable mBackground; private int backgroundColor; private Drawable deleteDrawable; private int intrinsicWidth; private int intrinsicHeight; SwipeToDeleteCallback(Context context) { mContext = context; mBackground = new ColorDrawable(); backgroundColor = Color.parseColor("#b80f0a"); mClearPaint = new Paint(); mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); deleteDrawable = ContextCompat.getDrawable(mContext, R.mipmap.ic_launcher_round); intrinsicWidth = deleteDrawable.getIntrinsicWidth(); intrinsicHeight = deleteDrawable.getIntrinsicHeight(); } @Override public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { return makeMovementFlags(0, ItemTouchHelper.LEFT); } @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) { return false; } @Override public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); View itemView = viewHolder.itemView; int itemHeight = itemView.getHeight(); boolean isCancelled = dX == 0 && !isCurrentlyActive; if (isCancelled) { clearCanvas(c, itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom()); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); return; } mBackground.setColor(backgroundColor); mBackground.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom()); mBackground.draw(c); int deleteIconTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2; int deleteIconMargin = (itemHeight - intrinsicHeight) / 2; int deleteIconLeft = itemView.getRight() - deleteIconMargin - intrinsicWidth; int deleteIconRight = itemView.getRight() - deleteIconMargin; int deleteIconBottom = deleteIconTop + intrinsicHeight; deleteDrawable.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom); deleteDrawable.draw(c); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } private void clearCanvas(Canvas c, Float left, Float top, Float right, Float bottom) { c.drawRect(left, top, right, bottom, mClearPaint); } @Override public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { return 0.7f; } } |
RecyclerViewAdapter.java:
In the RecyclerViewAdapter.java file, we will extend the RecyclerView.Adapter class and will override its onCreateViewHolder(), onBindViewHolder() methods.
package com.example.radioapp; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> { private ArrayList<String> data; public class MyViewHolder extends RecyclerView.ViewHolder { private TextView mTitle; RelativeLayout relativeLayout; public MyViewHolder(View itemView) { super(itemView); mTitle = itemView.findViewById(R.id.txtTitle); } } public RecyclerViewAdapter(ArrayList<String> data) { this.data = data; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_row, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.mTitle.setText(data.get(position)); } @Override public int getItemCount() { return data.size(); } public void removeItem(int position) { data.remove(position); notifyItemRemoved(position); } public void restoreItem(String item, int position) { data.add(position, item); notifyItemInserted(position); } public ArrayList<String> getData() { return data; } } |
Output 1:
Output 2:
Output 3:
Output 4: