Closed alimovshohrukh closed 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 Section
s. You need to perform some modification on the guideline, in order to make it works with SectionedRecyclerViewAdapter
.
I assume your adapter has more than 1 Section
s. 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
)
In SimpleItemTouchHelperCallback
, perform the modification to deal with multiple ItemTouchHelperAdapter
s. 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;
}
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;
}
getDashboardRecyclerViewOnItemClickListener().onItemMove
function, you are receiving the absolute adapter fromPosition and absolute adapter toPosition. What you need to do are fromPosition
to Section
by using sectionedRecyclerViewAdapter.getSectionForPosition
. Note, toPostion
should give you same Section
too. This is because in Paul Burke's SimpleItemTouchHelperCallback
, it contains the following code. @Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
Convert absolute position to relative position. For instance.
final NoteSection noteSection = (NoteSection)sectionedRecyclerViewAdapter.getSectionForPosition(fromPosition);
final List<Note> sectionNotes = noteSection.getNotes();
final int fromPositionInSection = sectionedRecyclerViewAdapter.getPositionInSection(fromPosition);
final int toPositionInSection = sectionedRecyclerViewAdapter.getPositionInSection(toPosition);
final Note from = sectionNotes.get(fromPositionInSection);
final Note to = sectionNotes.get(toPositionInSection);
Update your underlying data-structure accordingly.
Issue notifyItemMovedInSection
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
.
How about adding
ItemTouchHelperAdapter
interface to my adapter?