Чего я хочу добиться: иметь RecyclerView с GridLayoutManager, который поддерживает drag'n'drop и переупорядочивает элементы при перетаскивании.
Примечание: впервые разрабатывать что-либо с помощью перетаскивания.
Есть много тем о том, как реализовать эту функцию с помощью ListView, например: https://raw.githubusercontent.com/btownrippleman/FurthestProgress/master/FurthestProgress/src/com/anappforthat/android/languagelineup/DynamicListView.java
Однако примеры, как правило, содержат много кода, создавая растровые изображения перетаскиваемого представления, и View.startDrag(...)
что можно достичь того же результата, используя View.startDrag(...)
и RecyclerView с notifyItemAdded()
, notifyItemMoved()
и notifyItemRemoved()
поскольку они предоставляют анимацию перестановки.
Поэтому я немного поиграл и придумал это:
final CardAdapter adapter = new CardAdapter(list);
adapter.setHasStableIds(true);
adapter.setListener(new CardAdapter.OnLongClickListener() {
@Override
public void onLongClick(View view) {
ClipData data = ClipData.newPlainText("","");
View.DragShadowBuilder builder = new View.DragShadowBuilder(view);
final int pos = mRecyclerView.getChildAdapterPosition(view);
final Goal item = list.remove(pos);
mRecyclerView.setOnDragListener(new View.OnDragListener() {
int prevPos = pos;
@Override
public boolean onDrag(View view, DragEvent dragEvent) {
final int action = dragEvent.getAction();
switch(action) {
case DragEvent.ACTION_DRAG_LOCATION:
View onTopOf = mRecyclerView.findChildViewUnder(dragEvent.getX(), dragEvent.getY());
int i = mRecyclerView.getChildAdapterPosition(onTopOf);
list.add(i, list.remove(prevPos));
adapter.notifyItemMoved(prevPos, i);
prevPos = i;
break;
case DragEvent.ACTION_DROP:
View underView = mRecyclerView.findChildViewUnder(dragEvent.getX(), dragEvent.getY());
int underPos = mRecyclerView.getChildAdapterPosition(underView);
list.add(underPos, item);
adapter.notifyItemInserted(underPos);
adapter.notifyDataSetChanged();
break;
}
return true;
}
});
view.startDrag(data, builder, view, 0);
}
});
mRecyclerView.setAdapter(adapter);
Эта часть кода вроде работы, я получаю обмен, но очень нестабильный/шаткий, и иногда, когда он обновляет всю сетку, она перестраивается обратно в исходный порядок или что-то случайное. В любом случае, приведенный выше код - это только моя первая быстрая попытка, и мне действительно интересно знать, есть ли какой-нибудь стандартный/лучший метод перетаскивания с помощью ReyclerView или же правильный способ его решения остается тем же, что был использован для ListViews в течение многих лет?