我对RecyclerView的ItemTouchHelper有疑问。
我正在制作一个游戏。游戏板实际上是RecyclerView。 RecyclerView的GridLayoutManager具有一些跨度计数。我想实现拖放recyclerview的项目。任何项目都可以拖动所有方向(向上,向下,向左,向右)。
private void initializeLayout() {
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutFrozen(true);
recyclerView.setNestedScrollingEnabled(false);
// set layout manager
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), BOARD_SIZE,
LinearLayoutManager.VERTICAL, true);
recyclerView.setLayoutManager(layoutManager);
// Extend the Callback class
ItemTouchHelper.Callback itemTouchCallback = new ItemTouchHelper.Callback() {
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
Log.w(TAG, "onMove");
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// Application does not include swipe feature.
}
@Override
public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
Log.d(TAG, "onMoved");
// this is calling every time, but I need only when user dropped item, not after every onMove function.
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END;
int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
};
ItemTouchHelper touchHelper = new ItemTouchHelper(itemTouchCallback);
touchHelper.attachToRecyclerView(recyclerView);
}
那么,当我仍然在RecyclerView上拖动项目时,为什么ItemTouchHelper的onMoved函数有效?我怎样才能做到这一点?
在拖放项目时,可以多次调用onMove(),但clearView()将被调用一次。因此,您可以使用它来指示拖动已结束(丢弃已发生)。并使用两个变量dragFrom和dragTo来跟踪已完成的“拖放”中的实际位置。
private ItemTouchHelper.Callback dragCallback = new ItemTouchHelper.Callback() {
int dragFrom = -1;
int dragTo = -1;
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(ItemTouchHelper.UP|ItemTouchHelper.DOWN|ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT,
0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
if(dragFrom == -1) {
dragFrom = fromPosition;
}
dragTo = toPosition;
adapter.onItemMove(fromPosition, toPosition);
return true;
}
private void reallyMoved(int from, int to) {
// I guessed this was what you want...
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if(dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
reallyMoved(dragFrom, dragTo);
}
dragFrom = dragTo = -1;
}
};
adapter.onItemMove(fromPosition,toPosition)如下所示:
list.add(toPosition, list.remove(fromPosition));
notifyItemMoved(fromPosition, toPosition);
onSelectedChanged(RecyclerView.ViewHolder, int)
回调提供有关当前actionState的信息:
- ACTION_STATE_IDLE
:
- ACTION_STATE_DRAG
- ACTION_STATE_SWIPE
因此,您可以跟踪订单是否更改,当状态更改为ACTION_STATE_IDLE
时,您可以执行您需要做的事情!
例:
private final class MyCallback extends ItemTouchHelper.Callback {
private boolean mOrderChanged;
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// Check if positions of viewHolders correspond to underlying model, and if not, flip the items in the model and set the mOrderChanged flag
mOrderChanged = true;
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_IDLE && mOrderChanged) {
doSomething();
mOrderChanged = false;
}
}
您必须在适配器中实现OnMove侦听器:
Collections.swap(youCoolList, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
喜欢这个男人在做https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf#.blviq6jxp
特殊网格示例https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.xb74uu7ke
我做了一些测试,onSelectedChanged(RecyclerView.ViewHolder?, Int)
似乎对我来说最可靠的是检测到手势的结束(掉落)。每当拖动项目并传递ACTION_STATE_DRAG
的动作状态时,都会调用该方法。当拖动结束时,调用动作状态为ACTION_STATE_IDLE
。
请参阅下面的解决方案onItemDrag(Int, Int)
回调用于在拖动项目时重新排序适配器中的项目。另一方面,onItemDragged(Int, Int)
回调用于在手势结束时更新数据库中的位置。
class ItemGestureHelper(private val listener: OnItemGestureListener) : ItemTouchHelper.Callback() {
interface OnItemGestureListener {
fun onItemDrag(fromPosition: Int, toPosition: Int): Boolean
fun onItemDragged(fromPosition: Int, toPosition: Int)
fun onItemSwiped(position: Int)
}
private var dragFromPosition = -1
private var dragToPosition = -1
// Other methods omitted...
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
// Item is being dragged, keep the current target position
dragToPosition = target.adapterPosition
return listener.onItemDrag(viewHolder.adapterPosition, target.adapterPosition)
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
listener.onItemSwiped(viewHolder.adapterPosition)
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
when (actionState) {
ItemTouchHelper.ACTION_STATE_DRAG -> {
viewHolder?.also { dragFromPosition = it.adapterPosition }
}
ItemTouchHelper.ACTION_STATE_IDLE -> {
if (dragFromPosition != -1 && dragToPosition != -1 && dragFromPosition != dragToPosition) {
// Item successfully dragged
listener.onItemDragged(dragFromPosition, dragToPosition)
// Reset drag positions
dragFromPosition = -1
dragToPosition = -1
}
}
}
}
}