androidandroid-recyclerviewswipeitemtouchhelperandroid-swipe

RecyclerView with different ItemTouchHelper for each item on the list


I'm trying to implement a Recycleview with different ItemTouchHelper for each item on the list.

The only way that I know is to add an ItemTouchHelper directly to the RecycleView and not to the item.

Example of what I'm trying to do:

I have a list with 4 items and all items I can swipe to the left.

*The list can have a lot of items.

Does someone know how to do that?


Solution

  • The idea

    So basically your your question is about how to add a unique ItemTouchHelper to each RecyclerView item based on the item type.

    Without going deeply into the details of how you want each item to differ in the ItemTouchHelper swipe action, like you said to add some button functionalities like copy, edit, and delete. I will be just to the point How to differ ItemTouchHelper's swipe for different items.

    Steps

    Step 1: Differentiate among RecyclerView items using a POJO field

    So, first you need to create a field in your POJO (typically an int or enum) that differentiates among different items.

    Step 2: Implement a custom ItemTouchHelper.SimpleCallback

    Create a custom ItemTouchHelper.SimpleCallback class that takes the list of the RecyclerView items into its constructor.

    Next, override onChildDraw() which is called by ItemTouchHelper on RecyclerView's onDraw() callback; and this is the right place as it's called whenever the RecyclerView draws its individual items.

    So, in this method you can implement how you want each item looks like when you swipe. And as it takes a ViewHolder instance, so you can get the swiped item position with ViewHolder.getAdapterPosition(), and from the provided list of items, you can get the swiped item of this paritcular positon.

    Example

    Here is a simple example that is a list of colors that reflects the background color whenever you swipe a certain item.

    This is how it looks like:

    POJO

    For the above mentioned step 1, I store the value into colorValue field

    class ColorItem {
    
        String colorName;
        int colorValue;
    
        public ColorItem(String colorName, int colorValue) {
            this.colorName = colorName;
            this.colorValue = colorValue;
        }
    
        public String getColorName() {
            return colorName;
        }
    
        public void setColorName(String colorName) {
            this.colorName = colorName;
        }
    
        public int getColorValue() {
            return colorValue;
        }
    
        public void setColorValue(int colorValue) {
            this.colorValue = colorValue;
        }
    }
    

    RecyclerView adapter (no fancy code)

    public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.CustomViewHolder> {
    
        List<ColorItem> mColors;
    
        // Constructor
        RecyclerAdapter(List<ColorItem> colors) {
            this.mColors = colors;
        }
    
        @NonNull
        @Override
        public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
            View listItem = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_item, parent, false);
            return new CustomViewHolder(listItem);
        }
    
        @Override
        public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
            holder.tvColorName.setText(mColors.get(position).getColorName());
        }
    
        @Override
        public int getItemCount() {
            return mColors.size();
        }
    
        class CustomViewHolder extends RecyclerView.ViewHolder implements {
    
            TextView tvColorName;
    
            CustomViewHolder(@NonNull View listItem) {
                super(listItem);
                tvColorName = listItem.findViewById(R.id.tvColorName);
            }
    
          
        }
    }
    

    Custom ItemTouchHelper.SimpleCallback

    
    public class ItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
    
        private final List<ColorItem> mColorItems;
        private Context mContext;
    
        public interface OnTouchListener {
            void onSwiped(RecyclerView.ViewHolder viewHolder, int direction);
        }
    
        private OnTouchListener mOnTouchListener;
    
        public ItemSwipeCallback(Context context, List<ColorItem> items, int dragDirs, int swipeDirs, OnTouchListener onTouchListener) {
            super(dragDirs, swipeDirs);
            mContext = context;
            mColorItems = items;
            mOnTouchListener = onTouchListener;
        }
    
    
        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            return false;
        }
    
        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            mOnTouchListener.onSwiped(viewHolder, direction);
        }
    
        @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);
    
            // Getting the swiped item
            ColorItem item = mColorItems.get(viewHolder.getAdapterPosition());
    
            // Get the color of the swiped item (the thing that differentiates among items)
            ColorDrawable background = new ColorDrawable(mContext.getResources().getColor(item.getColorValue()));
    
            // Changing the color of the background item
            View itemView = viewHolder.itemView;
            int backgroundCornerOffset = 25; //so mBackground is behind the rounded corners of itemView
    
            if (dX > 0) { // Swiping to the right
                background.setBounds(itemView.getLeft(), itemView.getTop(),
                        itemView.getLeft() + ((int) dX) + backgroundCornerOffset, itemView.getBottom());
            } else if (dX < 0) { // Swiping to the left
                background.setBounds(itemView.getRight() + ((int) dX) - backgroundCornerOffset,
                        itemView.getTop(), itemView.getRight(), itemView.getBottom());
            } else { // view is unSwiped
                background.setBounds(0, 0, 0, 0);
            }
    
            background.draw(c);
    
        }
    }
    

    Activity

    public class MainActivity extends AppCompatActivity {
    
        ArrayList<ColorItem> mColors;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mColors = new ArrayList<>();
            populateColors();
            setupRecyclerView();
    
        }
    
        private void setupRecyclerView() {
            RecyclerAdapter adapter = new RecyclerAdapter(this, mColors);
            RecyclerView recyclerview = findViewById(R.id.recyclerview);
            RecyclerView.LayoutManager layoutMgr = new LinearLayoutManager(getApplicationContext());
            recyclerview.setLayoutManager(layoutMgr);
            recyclerview.setAdapter(adapter);
    
            ItemTouchHelper helper = new ItemTouchHelper(new ItemSwipeCallback(this, mColors,
                    0, ItemTouchHelper.RIGHT, new ItemSwipeCallback.OnTouchListener() {
    
                @Override
                public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                    // Do something here
                }
            }));
    
            helper.attachToRecyclerView(recyclerview);
        }
    
        private void populateColors() {
            mColors.add(new ColorItem("Red", R.color.red));
            mColors.add(new ColorItem("White", R.color.white));
            mColors.add(new ColorItem("Green", R.color.green));
            mColors.add(new ColorItem("Yellow", R.color.yellow));
            mColors.add(new ColorItem("Black", R.color.black));
            mColors.add(new ColorItem("Red", R.color.red));
            mColors.add(new ColorItem("White", R.color.white));
            mColors.add(new ColorItem("Green", R.color.green));
            mColors.add(new ColorItem("Yellow", R.color.yellow));
            mColors.add(new ColorItem("Black", R.color.black));
            mColors.add(new ColorItem("Red", R.color.red));
            mColors.add(new ColorItem("White", R.color.white));
            mColors.add(new ColorItem("Green", R.color.green));
            mColors.add(new ColorItem("Yellow", R.color.yellow));
            mColors.add(new ColorItem("Black", R.color.black));
        }
    
    }