Перетаскивание RecyclerView не работает с несколькими типами представлений
Я пытаюсь использовать RecyclerView с вертикальным LinearLayoutManager для отображения элементов списка. Этот список может содержать несколько различных типов элементов (различные макеты), и он может быть переупорядочен пользователем с помощью перетаскивания.
Для типов элементов, как описано в документации Android, я переопределил метод getItemType, чтобы обрабатывать различные типы представлений в утилите и обрабатывать их в onCreateViewHolder и onBindViewHolder. Это работает как шарм.
Для изменения порядка перетаскивания я использовал ItemTouchHelper.Callback (вдохновленный этим примером проекта). Это тоже хорошо работает.
Проблема возникает, когда я пытаюсь использовать разные типы элементов и поведение перетаскивания. Пока перетаскивание происходит между элементами одного типа, это работает хорошо, но когда я перетаскиваю представление типа A поверх представления типа B, остановка перетаскивания и представление возвращаются в исходное положение.
Вот мой код:
MyFragment.java
public class MyFragment extends Fragment implements MyAdapter.Listener {
private MyViewModel mViewModel;
private RecyclerView mRecyclerView;
private MyAdapter mAdapter;
private ItemTouchHelper mItemTouchHelper;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment, container, false);
mRecyclerView = root.findViewById(R.id.recyclerView);
mAdapter = new MyAdapter(this);
mRecyclerView.setAdapter(mAdapter);
mItemTouchHelper = new ItemTouchHelper(new MyDragHelperCallback(mAdapter));
mItemTouchHelper.attachToRecyclerView(mRecyclerView);
mViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);
mViewModel.addObserver(this, new Observer<List<Item>>() {
@Override
public void onChanged(@Nullable List<Item> items) {
mAdapter.updateList(items);
}
});
mAdapter.updateList(mViewModel.getList());
return root;
}
@Override
public void onStartDragRequest(@NonNull RecyclerView.ViewHolder viewHolder) {
mItemTouchHelper.startDrag(viewHolder);
}
}
MyDragHelperCallback.java
public class MyDragHelperCallback extends ItemTouchHelper.Callback {
private static final int DRAG_MOVEMENT_FLAGS = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
@NonNull
private MyDragListener mListener;
public MyDragHelperCallback(@NonNull MyDragListener listener) {
mListener = listener;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (!(recyclerView.getLayoutManager() instanceof LinearLayoutManager)) {
throw new IllegalArgumentException("Should only be used with a LinearLayoutManager");
}
return makeMovementFlags(DRAG_MOVEMENT_FLAGS, 0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mListener.onItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// Nothing to do
}
}
MyDragListener.java
public interface MyDragListener {
void onItemMoved(int from, int to);
}
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyHolder> implements MyDragListener {
@Nullable
private List<Item> mList;
public void updateList(@Nullable List<Item> list) {
mList = list;
notifyDataSetChanged();
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
return new MyHolderBis(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bis, parent, false));
}
return new MyHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
}
@Override
public void onBindViewHolder(final MyHolder holder, int position) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mListener.onStartDragRequest(holder);
return true;
}
});
// bind views to data
}
@Override
public int getItemCount() {
return mList != null ? mList.size() : 0;
}
@Override
public int getItemViewType(int position) {
return mList.get(position).getType();
}
@Override
public void onItemMoved(int from, int to) {
notifyItemMoved(from, to);
}
}
Я что-то пропустил? Или это просто возможно достичь?
Спасибо за все ваши ответы!