【问题标题】:how to create RecyclerView drag and drop (swap 2 item positions version)如何创建 RecyclerView 拖放(交换 2 个项目位置版本)
【发布时间】:2019-09-29 21:30:13
【问题描述】:

我有 ItemTouchHelper 类,它使用滑动和拖放来执行操作。但我想改变拖放行为。它应该交换 2 个元素的位置,我拖动的第一个元素和放置它的另一个元素的位置。我想交换拖放位置的项目。不要改变它们之间所有项目的位置。

怎么做

这是我的拖放类

public class ItemTouchHelper extends 
androidx.recyclerview.widget.ItemTouchHelper.Callback {

private Drawable icon;
private Context context;
private ColorDrawable background;
private final ItemTouchHelperListener dragDropListener;

public ItemTouchHelper(Context context, Drawable icon,
                       ItemTouchHelperListener dragDropListener) {
    this.icon = icon;
    this.dragDropListener = dragDropListener;
    this.context = context;
    this.background = new ColorDrawable(context.getResources().getColor(R.color.deleteItem));
}

@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
                        @NonNull RecyclerView.ViewHolder viewHolder,
                        float dX, float dY,
                        int actionState, boolean isCurrentlyActive) {
    super.onChildDraw(c, recyclerView, viewHolder, dX,
            dY, actionState, isCurrentlyActive);
    View itemView = viewHolder.itemView;

    int iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
    int iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
    int iconBottom = iconTop + icon.getIntrinsicHeight();

    if (dX > 0) {
        background = new ColorDrawable(context.getResources().getColor(R.color.deleteItem));

        iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
        iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
        iconBottom = iconTop + icon.getIntrinsicHeight();

        int iconRight = itemView.getLeft() + iconMargin + icon.getIntrinsicWidth();
        int iconLeft = itemView.getLeft() + iconMargin;

        icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);

        background.setBounds(itemView.getLeft(), itemView.getTop(),
                itemView.getLeft() + ((int) dX),
                itemView.getBottom());
    } else if (dX < 0) {
        int iconRight = itemView.getRight() - iconMargin;
        int iconLeft = itemView.getRight() - iconMargin - icon.getIntrinsicWidth();
        icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
        background.setBounds(itemView.getRight(), itemView.getTop(),
                itemView.getRight() + ((int) dX),
                itemView.getBottom());
    } else {
        background.setBounds(0, 0, 0, 0);
        icon.setBounds(0, 0, 0, 0);
    }

    background.draw(c);
    icon.draw(c);
}

@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder,
                     int direction) {
    dragDropListener.deleteElementDialog(viewHolder.getAdapterPosition());
}

@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
    int dragFlags = UP | DOWN;
    int swipeFlags = START | END;
    return makeMovementFlags(dragFlags, swipeFlags);
}

@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder,
                      @NonNull RecyclerView.ViewHolder target) {
    dragDropListener.onRowMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    return true;
}

@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
                              int actionState) {
    if (actionState != ACTION_STATE_IDLE && actionState != ACTION_STATE_SWIPE) {
        dragDropListener.onRowSelected(viewHolder);
    }
    super.onSelectedChanged(viewHolder, actionState);
}

@Override
public void clearView(@NonNull RecyclerView recyclerView,
                      @NonNull RecyclerView.ViewHolder viewHolder) {
    super.clearView(recyclerView, Objects.requireNonNull(viewHolder));
    dragDropListener.onRowClear(Objects.requireNonNull(viewHolder));
}

@Override
public boolean isLongPressDragEnabled() {
    return true;
}

}

这是我的 ItemTouchHelperListener:

    public void setItemTouchHelperListener() {
    ItemTouchHelperListener itemTouchHelperListener = new 
   ItemTouchHelperListener() {
        @Override
        public void onRowMoved(int fromPosition, int toPosition) {
            presenter.rowMoved(fromPosition, toPosition);
        }

        @Override
        public void onRowSelected(RecyclerView.ViewHolder myViewHolder) {
            if (myViewHolder instanceof ElementsAdapter.ElementsViewHolder) {
                elementsAdapter.rowSelected((ElementsAdapter.ElementsViewHolder) myViewHolder);
                presenter.rowSelected(myViewHolder.getAdapterPosition());
            }
        }

        @Override
        public void onRowClear(RecyclerView.ViewHolder myViewHolder) {
            if (myViewHolder instanceof ElementsAdapter.ElementsViewHolder) {
                elementsAdapter.rowClear((ElementsAdapter.ElementsViewHolder) myViewHolder);
                presenter.rowClear(myViewHolder.getAdapterPosition());
            }
        }

        @Override
        public void deleteElementDialog(int adapterPosition) {
            createDeleteDialog(adapterPosition);
        }
    };

【问题讨论】:

  • 包含嵌入式视频演示或显示您想要的行为的链接会很有帮助。例如,很难想象“它被放置在哪里”是什么意思......因为通常被拖动的项目将暂停在 两个 元素之间。

标签: java android android-recyclerview drag-and-drop itemtouchhelper


【解决方案1】:

您可以通过使用 onMove() 方法注册拖动的项目和使用 clearView() 方法注册拖放的项目来实现此目的;然后修改你的RecyclerView适配器的数据源;因此您可以使用存储拖动项目的临时项目;然后将拖放的项目设置为拖动的项目;最后将临时物品放在掉落的物品上。

然后使用 RecyclerView 适配器 notifyItemChanged() 为这两个项目更新此更改的布局

注意:这里我禁用了滑动,因为您的问题主要是拖放

final int[] oldPos = new int[1];
final int[] newPos = new int[1];
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(

        ItemTouchHelper.UP |
                ItemTouchHelper.DOWN |
                ItemTouchHelper.LEFT |
                ItemTouchHelper.RIGHT,
        0) {
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        oldPos[0] = viewHolder.getAdapterPosition();
        newPos[0] = target.getAdapterPosition();
        return false;
    }

    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {

    }

    @Override
    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        moveItem(oldPos[0], newPos[0]);
    }
});


private void moveItem(int oldPos, int newPos) {
    Item temp = mItems.get(oldPos);
    mItems.set(oldPos, mItems.get(newPos));
    mItems.set(newPos, temp);
    mAdapter.notifyItemChanged(oldPos);
    mAdapter.notifyItemChanged(newPos);

}

结果

【讨论】:

  • Zain 我想你不明白我的问题。我的代码现在就像您建议的代码结果一样工作。但我不想那样做。我只想更改拖放项目的位置。不改变它们之间所有元素的位置
  • @Haris 请检查我更新的代码 .. 它现在适用于我
【解决方案2】:

我完全同意@Zain 的回答,但有一个问题,即假设您想用第三项替换第一项,然后您将单击并按住第三项并将其拖到第一项上。放下后,您会注意到第三个项目将再次移动到其原始位置,之后,两个项目都会正确更新。看起来不太好。

我刚刚稍微修改了@Zain 的答案。

private int fromPos = -1;
private int toPos = -1;

ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new 
ItemTouchHelper.SimpleCallback(
    ItemTouchHelper.UP | ItemTouchHelper.DOWN |
    ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0) {

@Override
public boolean onMove(@NonNull RecyclerView recyclerView,
                      @NonNull RecyclerView.ViewHolder viewHolder,   
                      @NonNull RecyclerView.ViewHolder target) {
    toPos = target.getAdapterPosition();
    return false;
}

@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder,
                     int direction) {}

@Override
public void onSelectedChange(@NonNull RecyclerView.ViewHolder 
                           viewHolder, int actionState) {
    switch(actionState){
          case ItemTouchHelper.ACTION_STATE_DRAG:{
             fromPos = viewHolder.getAdapterPosition();
             break; 
          }

          case ItemTouchHelper.ACTION_STATE_IDLE: {
              //Execute when the user dropped the item after dragging.
              if(fromPos != -1 && toPos != -1      
                 && fromPos != toPos) {
               moveItem(fromPos, toPos);
               fromPos = -1;
               toPos = -1; 
           } 
           break;
        }
}

private void moveItem(int oldPos, int newPos) {
   Item temp = mItems.get(oldPos);
   mItems.set(oldPos, mItems.get(newPos));
   mItems.set(newPos, temp);
   mAdapter.notifyItemChanged(oldPos);
   mAdapter.notifyItemChanged(newPos);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多