我想在我的
RecyclerView
中实现拖放。据我发现,实现此目的的最佳方法是将 ItemTouchHelper
附加到 RecyclerView
。
onSwiped()
工作正常,但 onMove()
永远不会被触发。
这就是我所做的:
EditIngredientsRecyclerViewAdapter premixableIngredientsAdapter = new EditIngredientsRecyclerViewAdapter(this, typeOfComponents);
GridLayoutManager gridLayoutManager1 = new GridLayoutManager(getContext(), 1);
recyclerView.setAdapter(premixableIngredientsAdapter);
recyclerView.setLayoutManager(gridLayoutManager1);
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
Log.d(TAG, "onMove: ");
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
Log.d(TAG, "onSwiped: ");
}
};
ItemTouchHelper touchHelper = new ItemTouchHelper(simpleItemTouchCallback);
touchHelper.attachToRecyclerView(recyclerView);
我忘记了两件事:
**1。将
SimpleCallback
更新为:
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
// Notify Adapter of the moved item!
recyclerView.getAdapter().notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
// No swipe action
}
@Override
public boolean isItemViewSwipeEnabled() {
// Disable swipe (dont override this method or return true, if you want to have swipe)
return false;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// Set movement flags to specify the movement direction
// final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT; <-- for all directions
// In this case only up and down is allowed
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
};
特别重要的是覆盖
getMovementFlags()
以指定拖动方向并通知适配器移动的 Item,就像我在 onMove()
中所做的那样
2。通过
itemTouchHelper.startDrag(viewHolderElement)
触发拖动:
我通过在 RecyclerViewAdapter 中创建一个小界面来做到这一点:
public interface OnStartDragListener {
void onStartDrag(RecyclerView.ViewHolder holder);
}
创建适配器时,传入新的 OnStartDragListenerElement,如下所示:
EditIngredientsRecyclerViewAdapter premixableIngredientsAdapter = new EditIngredientsRecyclerViewAdapter(this, typeOfComponents, new EditIngredientsRecyclerViewAdapter.OnStartDragListener() {
@Override
public void onStartDrag(RecyclerView.ViewHolder holder) {
touchHelper.startDrag(holder);
Log.d(TAG, "onStartDrag: ");
}
});
并在 Touchlistener 中调用
onStartDrag(viewHolder)
,在视图中放置一个按钮,如下所示:
holder.itemBinding.dragBtn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mOnStartDragListener.onStartDrag(holder);
return false;
}
});
我确信,有更有效的实现,一旦有人在这里发布一个,我会接受它。然而,这至少让它对我有用。
我列出了 ItemTouchHelper.SimpleCallback 和 ItemTouchHelper.Callback() 的代码。代码中列出了注释,以帮助分解发生的情况。
ItemTouchHelper.SimpleCallback 在Activity/Fragment下的RecyclerView实现中创建一个ItemTouchHelper.SimpleCallback对象。您需要重写 onMove() 和 onSwiped() 方法。
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT
) {
// You'll need to Override
override fun onMove(
recyclerView: RecyclerView,
viewHolder: ViewHolder,
target: ViewHolder
): Boolean {
// Get the position start position of the item
val startPosition = viewHolder.adapterPosition
// Get the endPosition, where you draged it to.
val endPosition = target.adapterPosition
// Submit start and end position to notifyItemMoved.
recyclerView.adapter?.notifyItemMoved(startPosition, endPosition)
// true if moved, false otherwise
return true
}
override fun onSwiped ...
如果你想创建一个CustomItemTouchCallback
创建一个扩展 ItemTouchHelper.Callback() 的 customItemTouchHelper 类,您需要重写 getMovementFlags()、onMove() 和 onSwiped()
class CustomItemTouchHelper(mContext: Context, val viewModel: MyViewModel) : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
val swipeFlags = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
return makeMovementFlags(dragFlags, swipeFlags)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val startPosition = viewHolder.adapterPosition
val endPosition = target.adapterPosition
recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
// true if moved, false otherwise
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val editList: MutableList<User>? = viewModel.usersList?.value as MutableList<User>?
val editListCopy = editList?.toMutableList()
editListCopy?.removeAt(viewHolder.adapterPosition)
viewModel.usersList?.postValue(editListCopy)
}
override fun isItemViewSwipeEnabled(): Boolean {
// Allows items to be swiped left or right.
return true
}
override fun isLongPressDragEnabled(): Boolean {
// Allows for long click so items can be dragged, moved up or down in the list.
return true
}
}
现在在您的 Activity 或 Fragment 中,您需要创建一个 CustomItemHelper 对象,然后将 RecyclerView 附加到它。
val rv = findViewById<RecyclerView>(R.id.recycler_view)
rv.apply {
...
val customItemTouchHelper = ItemTouchHelper(CustomItemTouchHelper(context, viewModel))
customItemTouchHelper.attachToRecyclerView(rv)
}
抱歉,我没有足够的声誉来在该问题下发表评论。尝试将
return false
更改为 return true
您的
ItemTouchHelper.SimpleCallback
应在构造函数中设置移动标志,并且 onMove 方法应返回 true
。
int moveFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.LEFT;
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(moveFlags, swipeFlags) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
Log.d(TAG, "onMove: ");
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
// Swap list items in adapter...
return true;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
Log.d(TAG, "onSwiped: ");
}
}