luizgrp / SectionedRecyclerViewAdapter

An Adapter that allows a RecyclerView to be split into Sections with headers and/or footers. Each Section can have its state controlled individually.
MIT License
1.68k stars 372 forks source link

Is it possible to use notifyItemMoved? #112

Closed alimovshohrukh closed 6 years ago

alimovshohrukh commented 6 years ago

How about adding ItemTouchHelperAdapter interface to my adapter?

  @Override
    public void onItemMove(int fromPosition, int toPosition) {
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onItemDismiss(int position) {

    }
yccheok commented 6 years ago

I believe you are following guideline in https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf . Yes. That is a very well written guideline and the provided information is correct.

It is a bit tricky to implement drag/move operation with SectionedRecyclerViewAdapter, as you need to deal with multiple Sections. You need to perform some modification on the guideline, in order to make it works with SectionedRecyclerViewAdapter.

  1. I assume your adapter has more than 1 Sections. Make all Section implements ItemTouchHelperAdapter. (In Paul Burke's example, it is RecyclerView.Adapter which implements ItemTouchHelperAdapter. But, for SectionedRecyclerViewAdapter, you should make Section implements ItemTouchHelperAdapter)

  2. In SimpleItemTouchHelperCallback, perform the modification to deal with multiple ItemTouchHelperAdapters. For instance

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
        if (source.getItemViewType() != target.getItemViewType()) {
            return false;
        }

        final int fromPosition = source.getAdapterPosition();
        final int toPosition = target.getAdapterPosition();
        // Notify the adapter of the move
        for (ItemTouchHelperAdapter mAdapter : mAdapters) {
            if (mAdapter.onItemMove(fromPosition, toPosition)) {
                break;
            }
        }
        return true;
    }
  1. I assume your Section A is not interested on the move operation done on Section B. This is what you need to do, in your Section code. if (section != this) { does the trick.
    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        SectionedRecyclerViewAdapter sectionedRecyclerViewAdapter = dashboardFragment.getSectionedRecyclerViewAdapter();

        if (fromPosition < 0 || toPosition < 0) {
            return false;
        }

        final int itemCount = sectionedRecyclerViewAdapter.getItemCount();
        if (fromPosition >= itemCount || toPosition >= itemCount) {
            return false;
        }

        Section section = sectionedRecyclerViewAdapter.getSectionForPosition(fromPosition);

        if (section != this) {
            return false;
        }

        dashboardFragment.getDashboardRecyclerViewOnItemClickListener().onItemMove(fromPosition, toPosition);

        // Returning correct boolean is importatnt for optimization purpose.
        return true;
    }
  1. In getDashboardRecyclerViewOnItemClickListener().onItemMove function, you are receiving the absolute adapter fromPosition and absolute adapter toPosition. What you need to do are
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
        if (source.getItemViewType() != target.getItemViewType()) {
            return false;
        }

Note, there's no generalized solution for implementing drag-n-move operation. Hence, it takes some pain and effort :)

If possible, you may consider using DiffUtil (Instead of issue notifyItemMovedInSection manually). My experience is that, using DiffUtil, makes my code more generalized, and easier to maintain. I need not worry issuing wrong notify... message to adapter. But, again, it also takes some effort to implement DiffUtil correctly. Please refer to https://github.com/luizgrp/SectionedRecyclerViewAdapter/issues/108#issuecomment-385189455 for more information regarding DiffUtil.