receives events when user performs these actions ( like swipe and drag ). In this post will we see how to delete items of recyclerView item on swipe and we will also implement the undo operation on swiped item .
XML Layout
Define XML Layout inside res/layout folder.
main xml layout containing recyclerView Widget.
file : fragment_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.tutorialsbuzz.recyclerviewitemleftswipe.MainActivityFragment" tools:showIn="@layout/activity_main"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> </RelativeLayout>
file : row_item.xml
This xml layout represents the row items of recyclerView .
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <!-- Swipe Layout--> <include layout="@layout/swipe_row_item" /> <!-- Regular Layout--> <include layout="@layout/regular_row_item" /> </FrameLayout>
file : regular_row_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/regularLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/list_item" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Regular Layout" android:textSize="28sp" /> </LinearLayout>
file : swipe_row_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/swipeLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/swipebg" android:orientation="horizontal" android:padding="@dimen/activity_horizontal_margin" android:visibility="visible" android:weightSum="3"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/archived_label" android:textColor="@android:color/white" android:textSize="24sp" /> <TextView android:id="@+id/undo" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="2" android:gravity="end" android:paddingBottom="5dp" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="5dp" android:text="@string/undo_label" android:textColor="@android:color/white" android:textSize="22sp" android:textStyle="bold" /> </LinearLayout>
ItemTouchHelper
Create a class SwipeUtil and extend it to ItemTouchHelper.SimpleCallback and Override the method of "ItemTouchHelper.SimpleCallback" class , onChildDraw method contains the logic for drawing Canvas while swiping items of recyclerView , onSwipe Call is called on Item Swiped .
file : SwipeUtil.java
package com.tutorialsbuzz.recyclerviewitemleftswipe.SwipeUtil; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; import com.tutorialsbuzz.recyclerviewitemleftswipe.R; public abstract class SwipeUtil extends ItemTouchHelper.SimpleCallback { private Drawable background; private Drawable deleteIcon; private int xMarkMargin; private boolean initiated; private Context context; private int leftcolorCode; private String leftSwipeLable; public SwipeUtil(int dragDirs, int swipeDirs, Context context) { super(dragDirs, swipeDirs); this.context = context; } private void init() { background = new ColorDrawable(); xMarkMargin = (int) context.getResources().getDimension(R.dimen.ic_clear_margin); deleteIcon = ContextCompat.getDrawable(context, android.R.drawable.ic_menu_delete); deleteIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP); initiated = true; } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { return false; } @Override public abstract void onSwiped(RecyclerView.ViewHolder viewHolder, int direction); @Override public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { return super.getSwipeDirs(recyclerView, viewHolder); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { View itemView = viewHolder.itemView; if (!initiated) { init(); } int itemHeight = itemView.getBottom() - itemView.getTop(); //Setting Swipe Background ((ColorDrawable) background).setColor(getLeftcolorCode()); background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom()); background.draw(c); int intrinsicWidth = deleteIcon.getIntrinsicWidth(); int intrinsicHeight = deleteIcon.getIntrinsicWidth(); int xMarkLeft = itemView.getRight() - xMarkMargin - intrinsicWidth; int xMarkRight = itemView.getRight() - xMarkMargin; int xMarkTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2; int xMarkBottom = xMarkTop + intrinsicHeight; //Setting Swipe Icon deleteIcon.setBounds(xMarkLeft, xMarkTop + 16, xMarkRight, xMarkBottom); deleteIcon.draw(c); //Setting Swipe Text Paint paint = new Paint(); paint.setColor(Color.WHITE); paint.setTextSize(48); paint.setTextAlign(Paint.Align.CENTER); c.drawText(getLeftSwipeLable(), xMarkLeft + 40, xMarkTop + 10, paint); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } public String getLeftSwipeLable() { return leftSwipeLable; } public void setLeftSwipeLable(String leftSwipeLable) { this.leftSwipeLable = leftSwipeLable; } public int getLeftcolorCode() { return leftcolorCode; } public void setLeftcolorCode(int leftcolorCode) { this.leftcolorCode = leftcolorCode; } }
RecyclerView Adapter
Create a class RVAdapter and extend it RecyclerView.Adapter and override the all necessary methods requires to inflate items of recyclerView .
To Keep track of swiped Items create arraylist "itemsPendingRemoval"
- on Swipe add to item to itemsPendingRemoval list.
- on Undo Remove item from itemsPendingRemoval list.
file : RVAdapter.java
package com.tutorialsbuzz.recyclerviewitemleftswipe.Adapter; import android.os.Handler; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.tutorialsbuzz.recyclerviewitemleftswipe.R; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class RVAdapter extends RecyclerView.Adapter<ItemViewHolder> { private List<String> dataList; private List<String> itemsPendingRemoval; private static final int PENDING_REMOVAL_TIMEOUT = 3000; // 3sec private Handler handler = new Handler(); // hanlder for running delayed runnables HashMap<String, Runnable> pendingRunnables = new HashMap<>(); // map of items to pending runnables, so we can cancel a removal if need be public RVAdapter(List<String> dataList) { this.dataList = dataList; itemsPendingRemoval = new ArrayList<>(); } @Override public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item, parent, false); return new ItemViewHolder(itemView); } @Override public void onBindViewHolder(ItemViewHolder holder, int position) { final String data = dataList.get(position); if (itemsPendingRemoval.contains(data)) { /** {show swipe layout} and {hide regular layout} */ holder.regularLayout.setVisibility(View.GONE); holder.swipeLayout.setVisibility(View.VISIBLE); holder.undo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { undoOpt(data); } }); } else { /** {show regular layout} and {hide swipe layout} */ holder.regularLayout.setVisibility(View.VISIBLE); holder.swipeLayout.setVisibility(View.GONE); holder.listItem.setText(data); } } private void undoOpt(String customer) { Runnable pendingRemovalRunnable = pendingRunnables.get(customer); pendingRunnables.remove(customer); if (pendingRemovalRunnable != null) handler.removeCallbacks(pendingRemovalRunnable); itemsPendingRemoval.remove(customer); // this will rebind the row in "normal" state notifyItemChanged(dataList.indexOf(customer)); } @Override public int getItemCount() { return dataList.size(); } public void pendingRemoval(int position) { final String data = dataList.get(position); if (!itemsPendingRemoval.contains(data)) { itemsPendingRemoval.add(data); // this will redraw row in "undo" state notifyItemChanged(position); // let's create, store and post a runnable to remove the data Runnable pendingRemovalRunnable = new Runnable() { @Override public void run() { remove(dataList.indexOf(data)); } }; handler.postDelayed(pendingRemovalRunnable, PENDING_REMOVAL_TIMEOUT); pendingRunnables.put(data, pendingRemovalRunnable); } } public void remove(int position) { String data = dataList.get(position); if (itemsPendingRemoval.contains(data)) { itemsPendingRemoval.remove(data); } if (dataList.contains(data)) { dataList.remove(position); notifyItemRemoved(position); } } public boolean isPendingRemoval(int position) { String data = dataList.get(position); return itemsPendingRemoval.contains(data); } }
View Holder
file : ItemViewHolder.java
package com.tutorialsbuzz.recyclerviewitemleftswipe.Adapter; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import com.tutorialsbuzz.recyclerviewitemleftswipe.R; public class ItemViewHolder extends RecyclerView.ViewHolder { public LinearLayout regularLayout; public LinearLayout swipeLayout; public TextView listItem; public TextView undo; public ItemViewHolder(View view) { super(view); regularLayout = (LinearLayout) view.findViewById(R.id.regularLayout); listItem = (TextView) view.findViewById(R.id.list_item); swipeLayout = (LinearLayout) view.findViewById(R.id.swipeLayout); undo = (TextView) view.findViewById(R.id.undo); } }
Fragment
Create a class MainActivityFragment inside this class set the above define adapter and swipeUtil to recyclerView .
file : MainActivityFragment.java
package com.tutorialsbuzz.recyclerviewitemleftswipe; import android.support.v4.app.Fragment; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.tutorialsbuzz.recyclerviewitemleftswipe.Adapter.RVAdapter; import com.tutorialsbuzz.recyclerviewitemleftswipe.SwipeUtil.SwipeUtil; import java.util.ArrayList; import java.util.List; /** * A placeholder fragment containing a simple view. */ public class MainActivityFragment extends Fragment { private RecyclerView mRecyclerView; public MainActivityFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View mView = inflater.inflate(R.layout.fragment_main, container, false); mRecyclerView = (RecyclerView) mView.findViewById(R.id.recyclerView); return mView; } @Override public void onResume() { super.onResume(); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(linearLayoutManager); RVAdapter rvAdapter = new RVAdapter(getData()); mRecyclerView.setAdapter(rvAdapter); setSwipeForRecyclerView(); } private List<String> getData() { List<String> modelList = new ArrayList<>(); for (int i = 0; i < 10; i++) { modelList.add("data item : " + i); } return modelList; } private void setSwipeForRecyclerView() { SwipeUtil swipeHelper = new SwipeUtil(0, ItemTouchHelper.LEFT, getActivity()) { @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { int swipedPosition = viewHolder.getAdapterPosition(); RVAdapter adapter = (RVAdapter) mRecyclerView.getAdapter(); adapter.pendingRemoval(swipedPosition); } @Override public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int position = viewHolder.getAdapterPosition(); RVAdapter adapter = (RVAdapter) mRecyclerView.getAdapter(); if (adapter.isPendingRemoval(position)) { return 0; } return super.getSwipeDirs(recyclerView, viewHolder); } }; ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(swipeHelper); mItemTouchHelper.attachToRecyclerView(mRecyclerView); //set swipe label swipeHelper.setLeftSwipeLable("Archive"); //set swipe background-Color swipeHelper.setLeftcolorCode(ContextCompat.getColor(getActivity(), R.color.swipebg)); } }
GitHub : https://github.com/hdpavan/RecyclerViewItemTouchHelperSwipe
4 comments:
good tutorial
Understandable. Thank you!
Perfect! Thanks!!
Thanks solution...
Post a Comment