跳转至

RecyclerView高级特性——拖拽排序以及滑动删除

RecyclerView高级特性系列:


RecyclerView支持拖拽排序以及滑动删除,实现过程也比较简单。

下面先上一段demo效果视频:

主要流程如下:

  1. 定义拖拽操作、滑动删除接口
  2. Adapter中实现第一步的接口,这里主要是体现对数据的操作
  3. 自定义Callback实现android.support.v7.widget.helper.ItemTouchHelper.Callback,此Callback就是RecyclerView实现拖拽、滑动删除的关键
  4. 创建ItemTouchHelperattachToRecyclerView

下面上代码

1. 定义拖拽、滑动操作的接口

public interface IDragSwipe {
    /**
     * 两个Item交换位置
     * @param fromPosition 第一个Item的位置
     * @param toPosition 第二个Item的位置
     */
    void onItemSwapped(int fromPosition, int toPosition);

    /**
     * 删除Item
     * @param position 待删除Item的位置
     */
    void onItemDeleted(int position);

    /**
     * Item标记完成
     * @param position Item的位置
     */
    void onItemDone(int position);
}

这里定义了三个方法,交换、删除以及标记完成

2. Adapter实现该接口

public class TodoTaskAdapter extends BaseQuickAdapter<TodoTask, BaseViewHolder> implements IDragSwipe {
    ...

    @Override
    public void onItemSwapped(int fromPosition, int toPosition) {
        Collections.swap(getData(), fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onItemDeleted(int position) {
        Toast.makeText(mContext, "onItemDeleted", Toast.LENGTH_SHORT).show();
        mData.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public void onItemDone(int position) {
        Toast.makeText(mContext, "onItemDone", Toast.LENGTH_SHORT).show();
        mData.remove(position);
        notifyItemRemoved(position);
    }
}

如上所示

  • 交换时使用Collections.swap将对应位置的数据进行交换,然后通知数据有更改(notifyItemMoved以及notifyItemRemoved)会有默认的动画效果。
  • 删除以及标记完成都是简单的移除了数据,然后通知更新。这里可以按照自己的业务来,这里只是demo

3. 自定义Callback类,调用Adapter的交换、删除等操作方法

这步是重要的过程,我们先上全部的代码。

public class DragSwipeCallback extends android.support.v7.widget.helper.ItemTouchHelper.Callback {

    /** 通过此变量通知外界发生了排序、删除等操作 */
    private IDragSwipe mAdapter;

    public DragSwipeCallback(IDragSwipe adapter){
        // 注入IDragSwipe
        mAdapter = adapter;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        // 确定拖拽、滑动支持的方向
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

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

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

    /**
     * 拖拽、交换事件
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        mAdapter.onItemSwapped(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    /**
     * 滑动成功的事件
     */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        switch (direction) {
            case ItemTouchHelper.END: // START->END 标记完成事件
                mAdapter.onItemDone(viewHolder.getAdapterPosition());
                break;
            case ItemTouchHelper.START: // END->START 删除事件
                mAdapter.onItemDeleted(viewHolder.getAdapterPosition());
                break;
            default:
        }
    }

    /**
     * 拖拽、滑动时如何绘制列表
     * actionState只会为ACTION_STATE_DRAG或者ACTION_STATE_SWIPE
     */
     @Override
     public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
         switch (actionState) {
             case ItemTouchHelper.ACTION_STATE_DRAG:
                 // 拖拽时,如果是isCurrentlyActive,则设置translationZ,否则复位
                 viewHolder.itemView.setTranslationZ(SizeUtils.dp2px(isCurrentlyActive ? 4 : 0));
                 super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
                 break;
             case ItemTouchHelper.ACTION_STATE_SWIPE:
                 // 滑动时,对view的绘制
                 View rootView = viewHolder.itemView;
                 View contentView = rootView.findViewById(R.id.ll_content_root);
                 View actionView = rootView.findViewById(R.id.ll_action_root);
                 ImageView doneImageView = actionView.findViewById(R.id.iv_task_done);
                 View actionSpaceView = actionView.findViewById(R.id.view_action_space);
                 ImageView deleteImageView = actionView.findViewById(R.id.iv_task_delete);
                 if (dX < 0) {
                     deleteImageView.setImageResource(R.drawable.ic_delete_white_24dp);
                     deleteImageView.setBackgroundResource(R.color.ffff4081);
                     doneImageView.setImageDrawable(null);
                     doneImageView.setBackgroundResource(R.color.ffff4081);
                     actionSpaceView.setBackgroundResource(R.color.ffff4081);
                 } else {
                     doneImageView.setImageResource(R.drawable.ic_done_white_24dp);
                     doneImageView.setBackgroundResource(R.color.ff53c4ac);
                     deleteImageView.setImageDrawable(null);
                     deleteImageView.setBackgroundResource(R.color.ff53c4ac);
                     actionSpaceView.setBackgroundResource(R.color.ff53c4ac);
                 }
                 contentView.setTranslationX(dX);
                 break;
             default:
         }
     }

    /**
     * 在onSelectedChanged、onChildDraw、onChildDrawOver操作完成后可以在此进行清楚操作
     */
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        View rootView = viewHolder.itemView;
        View contentView = rootView.findViewById(R.id.ll_content_root);
        contentView.setTranslationX(0);
    }
}

4. 创建ItemTouchHelperattachToRecyclerView

创建TodoTaskAdapter、将其注入DragSwipeCallback类,然后注入ItemTouchHelper,最后attachToRecyclerView

mTodoTaskAdapter = new TodoTaskAdapter(queryTaskFromDB());
ItemTouchHelper.Callback callback = new DragSwipeCallback(mTodoTaskAdapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mTodoTaskAdapter);
touchHelper.attachToRecyclerView(mRecyclerView);

此处只是一个demo,让Adapter实现IDragSwipe接口,实际上本人觉得并不妥当。


最后更新: 2020年1月14日

评论