一个简单的自定义RecyclerView适配器(四)——拖拽、滑动

RecyclerView经常需要添加拖拽、滑动删除的功能,这里在前文的基础上,自定义一个适配器

适配器

继承前文的BaseRecyclerViewAdapter,拓展拖拽排序、滑动删除的功能

public abstract class BaseItemRecyclerViewAdapter extends BaseRecyclerViewAdapter{

    private int Tag = R.id.BaseQuickAdapter_dragging_support;
    private static final int NO_TOGGLE_VIEW = 0;
    protected int mToggleViewId = NO_TOGGLE_VIEW;
    protected ItemTouchHelper mItemTouchHelper;
    protected boolean itemDragEnabled = false;
    protected boolean itemSwipeEnabled = false;
    protected OnItemDragListener mOnItemDragListener;
    protected OnItemSwipeListener mOnItemSwipeListener;
    protected boolean mDragOnLongPress = true;

    protected View.OnTouchListener mOnToggleViewTouchListener;
    protected View.OnLongClickListener mOnToggleViewLongClickListener;

    private static final String ERROR_NOT_SAME_ITEMTOUCHHELPER = "Item drag and item swipe should pass the same ItemTouchHelper";


    public BaseItemRecyclerViewAdapter(int layoutResId, List data) {
        super(layoutResId, data);
    }


    /**
     * To bind different types of holder and solve different the bind events
     *
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(K holder, int position) {
        super.onBindViewHolder(holder, position);
        int viewType = holder.getItemViewType();

        if (mItemTouchHelper != null && itemDragEnabled) {
            if (mToggleViewId != NO_TOGGLE_VIEW) {
                View toggleView = holder.getView(mToggleViewId);
                if (toggleView != null) {
                    toggleView.setTag(Tag, holder);
                    if (mDragOnLongPress) {
                        toggleView.setOnLongClickListener(mOnToggleViewLongClickListener);
                    } else {
                        toggleView.setOnTouchListener(mOnToggleViewTouchListener);
                    }
                }
            } else {
                holder.itemView.setTag(Tag, holder);
                holder.itemView.setOnLongClickListener(mOnToggleViewLongClickListener);
            }
        }
    }


    /**
     * 设置长按mToggleViewId触发拖动事件
     * 如果未设置mToggleViewId,则在长按item时触发拖动事件
     *
     * @param toggleViewId the toggle view's id
     */
    public void setToggleViewId(int toggleViewId) {
        mToggleViewId = toggleViewId;
    }

    /**
     * 如果为true,则拖动事件将在长按时触发,否则将在点击时触发。
     *
     * @param longPress 默认为true
     */
    public void setToggleDragOnLongPress(boolean longPress) {
        mDragOnLongPress = longPress;
        if (mDragOnLongPress) {
            mOnToggleViewTouchListener = null;
            mOnToggleViewLongClickListener = new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if (mItemTouchHelper != null && itemDragEnabled) {
                        mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(Tag));
                    }
                    return true;
                }
            };
        } else {
            mOnToggleViewTouchListener = new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN
                            && !mDragOnLongPress) {
                        if (mItemTouchHelper != null && itemDragEnabled) {
                            mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(Tag));
                        }
                        return true;
                    } else {
                        return false;
                    }
                }
            };
            mOnToggleViewLongClickListener = null;
        }
    }

    /**
     * 开启拖动item功能
     * 长按时使用 itemView 作为toggleView。
     *
     * @param itemTouchHelper {@link ItemTouchHelper}
     */
    public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper) {
        enableDragItem(itemTouchHelper, NO_TOGGLE_VIEW, true);
    }

    /**
     * 开启拖动item的子view的功能
     * 长按时使用传入的 toggleViewId 作为toggleView。
     * @param itemTouchHelper {@link ItemTouchHelper}
     * @param toggleViewId    被拖动的itemView的子view的id
     * @param dragOnLongPress 如果为true,则拖动事件将在长按时触发,否则将在点击时触发。
     */
    public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper, int toggleViewId, boolean dragOnLongPress) {
        itemDragEnabled = true;
        mItemTouchHelper = itemTouchHelper;
        setToggleViewId(toggleViewId);
        setToggleDragOnLongPress(dragOnLongPress);
    }

    /**
     * 禁用拖动item功能
     */
    public void disableDragItem() {
        itemDragEnabled = false;
        mItemTouchHelper = null;
    }

    public boolean isItemDraggable() {
        return itemDragEnabled;
    }

    /**
     * 

启用滑动item功能

*/ public void enableSwipeItem() { itemSwipeEnabled = true; } public void disableSwipeItem() { itemSwipeEnabled = false; } public boolean isItemSwipeEnable() { return itemSwipeEnabled; } /** * 拖动接口 */ public interface OnItemDragListener { void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos); void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to); void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos); } /** * 拖动事件,在Activity中调用mAdapter.setOnItemDragListener(onItemDragListener) * @param onItemDragListener 拖动事件的回调。 */ public void setOnItemDragListener(OnItemDragListener onItemDragListener) { mOnItemDragListener = onItemDragListener; } public int getViewHolderPosition(RecyclerView.ViewHolder viewHolder) { return viewHolder.getAdapterPosition(); } /** * 拖动开始 * @param viewHolder */ public void onItemDragStart(RecyclerView.ViewHolder viewHolder) { if (mOnItemDragListener != null && itemDragEnabled) { mOnItemDragListener.onItemDragStart(viewHolder, getViewHolderPosition(viewHolder)); } } /** * 拖动中 * @param source * @param target */ public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { int from = getViewHolderPosition(source); int to = getViewHolderPosition(target); if (inRange(from) && inRange(to)) { if (from < to) { for (int i = from; i < to; i++) { Collections.swap(data, i, i + 1); } } else { for (int i = from; i > to; i--) { Collections.swap(data, i, i - 1); } } notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition()); } if (mOnItemDragListener != null && itemDragEnabled) { mOnItemDragListener.onItemDragMoving(source, from, target, to); } } /** * 拖动结束 * @param viewHolder */ public void onItemDragEnd(RecyclerView.ViewHolder viewHolder) { if (mOnItemDragListener != null && itemDragEnabled) { mOnItemDragListener.onItemDragEnd(viewHolder, getViewHolderPosition(viewHolder)); } } /** * 滑动接口 */ public interface OnItemSwipeListener { void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos); /** * 如果在onItemSwipeStart中更改视图 * 该方法要重置 * * @param pos 如果视图被刷过,则pos将为负数。 */ void clearView(RecyclerView.ViewHolder viewHolder, int pos); void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos); void onItemSwipeMoving(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive); } /** * 滑动事件,在Activity中调用mAdapter.setOnItemSwipeListener(OnItemSwipeListener) * @param listener 滑动事件的回调 */ public void setOnItemSwipeListener(OnItemSwipeListener listener) { mOnItemSwipeListener = listener; } /** * 滑动开始 * @param viewHolder */ public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder) { if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.onItemSwipeStart(viewHolder, getViewHolderPosition(viewHolder)); } } /** * 滑动结束 * @param viewHolder */ public void onItemSwipeClear(RecyclerView.ViewHolder viewHolder) { if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.clearView(viewHolder, getViewHolderPosition(viewHolder)); } } /** * 滑动刷新项目时调用,视图将从适配器中删除。 * @param viewHolder */ public void onItemSwiped(RecyclerView.ViewHolder viewHolder) { int pos = getViewHolderPosition(viewHolder); if (inRange(pos)) { data.remove(pos); notifyItemRemoved(viewHolder.getAdapterPosition()); } if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.onItemSwiped(viewHolder, getViewHolderPosition(viewHolder)); } } /** * 自定义侧滑删除动画 * @param canvas 空白的画布 * @param viewHolder 正在与用户交互的ViewHolder * @param dX 侧滑水平位移量 * @param dY 侧滑垂直位移量 * @param isCurrentlyActive */ public void onItemSwiping(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive) { if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.onItemSwipeMoving(canvas, viewHolder, dX, dY, isCurrentlyActive); } } private boolean inRange(int position) { return position >= 0 && position < data.size(); } }

拖动or滑动的回调类

ItemTouchHelper在RecyclerView的整个体系中,负责监听Item的手势操作,我们通过给它设置一个继承于ItemTouchHelper.Callback的子类,在其中处理Item的UI变化,就可以完成侧滑删除、拖动排序等操作
不了解的可以参考:https://www.jianshu.com/p/0bbc44cc1582

public class BaseItemTouchHelpCallback extends ItemTouchHelper.Callback{

    private BaseItemRecyclerViewAdapter mAdapter;

    public BaseItemTouchHelpCallback(BaseItemRecyclerViewAdapter mAdapter){
        this.mAdapter = mAdapter;
    }

    /**
     * 拖拽方向:上、下、左、右
     */
    private int mDragMoveFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
    public void setDragMoveFlags(int dragMoveFlags) {
        mDragMoveFlags = dragMoveFlags;
    }

    /**
     * 滑动方向:右滑
     */
    private int mSwipeMoveFlags = ItemTouchHelper.END;
    public void setSwipeMoveFlags(int swipeMoveFlags) {
        mSwipeMoveFlags = swipeMoveFlags;
    }

    /**
     * 是否可以通过长按来触发拖动操作,
     * @return 默认返回true,如果返回false,那么可以通过startDrag(ViewHolder)方法来触发某个特定Item的拖动的机制
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return false;
    }

    /**
     * 是否启动在任意位置滑动
     * @return true:在任意位置发生触摸事件时启用滑动操作
     */
    @Override
    public boolean isItemViewSwipeEnabled() {
        return mAdapter.isItemSwipeEnable();
    }

    /**
     * 拖拽的时候移动多少距离就判定为可以交换了,默认0.5F
     */
    private float mMoveThreshold = 0.1f;
    public void setMoveThreshold(float moveThreshold) {
        mMoveThreshold = moveThreshold;
    }
    @Override
    public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        return mMoveThreshold;
    }

    /**
     * 滑动的时候移动多少距离就判定为可以交换了
     */
    private float mSwipeThreshold = 0.7f;
    public void setSwipeThreshold(float swipeThreshold) {
        mSwipeThreshold = swipeThreshold;
    }
    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        return mSwipeThreshold;
    }

    private int Tag = R.id.BaseQuickAdapter_dragging_support;

    /**
     * 设置拖拽或滑动方向
     * 当用户拖拽或者滑动Item的时候需要告诉系统拖拽或者滑动的方向
     * @param recyclerView recyclerView
     * @param viewHolder 选中的viewHolder
     * @return
     */
    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        return makeMovementFlags(mDragMoveFlags, mSwipeMoveFlags);
    }

    /**
     * 滑动或拖动开始时调用
     * @param viewHolder 滑动或拖动的ViewHolder
     * @param actionState ViewHolder的状态,ACTION_STATE_DRAG拖拽,ACTION_STATE_SWIPE滑动
     */
    @Override
    public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
        if (viewHolder!= null){
            if (actionState == ItemTouchHelper.ACTION_STATE_DRAG ) {
                mAdapter.onItemDragStart(viewHolder);
//                viewHolder.itemView.setTag(Tag, true);
            } else if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE ) {
                mAdapter.onItemSwipeStart(viewHolder);
//                viewHolder.itemView.setTag(Tag, true);
            }
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    /**
     * 滑动或拖动结束时调用
     * @param recyclerView recyclerView
     * @param viewHolder 滑动或拖动的ViewHolder
     */
    @Override
    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        if (viewHolder.itemView.getTag(Tag) != null ) {//&& (Boolean) viewHolder.itemView.getTag(Tag)
            mAdapter.onItemDragEnd(viewHolder);
//            viewHolder.itemView.setTag(Tag, false);
        }
        if (viewHolder.itemView.getTag(Tag) != null ) {
            mAdapter.onItemSwipeClear(viewHolder);
//            viewHolder.itemView.setTag(Tag, false);
        }
    }

    /**
     * 当Item被拖拽的时候回调
     * @param recyclerView recyclerView
     * @param source 拖拽的viewHolder
     * @param target 目的拖拽viewHolder
     * @return true: ViewType相同调用onMoved;设置source.getItemViewType() == target.getItemViewType();不同 ViewType 之间不能进行拖拽
     */
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, @NonNull RecyclerView.ViewHolder target) {
        return true;
    }

    /**
     * 当onMove返回true时回调,刷新列表
     * @param recyclerView recyclerView
     * @param source 拖拽的viewHolder
     * @param fromPos
     * @param target 目的拖拽viewHolder
     * @param toPos
     * @param x
     * @param y
     */
    @Override
    public void onMoved(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, int fromPos, @NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
        super.onMoved(recyclerView, source, fromPos, target, toPos, x, y);
        mAdapter.onItemDragMoving(source, target);
    }

    /**
     * 当Item被滑动的时候回调
     * @param viewHolder 要删除的item
     * @param direction 表示滑动的方向
     */
    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        mAdapter.onItemSwiped(viewHolder);
    }

    /**
     * 自定义侧滑删除动画时
     * @param c
     * @param recyclerView recyclerView
     * @param viewHolder 正在与用户交互的ViewHolder
     * @param dX 侧滑水平位移量
     * @param dY 侧滑垂直位移量
     * @param actionState 状态
     * @param isCurrentlyActive
     */
    @Override
    public void onChildDrawOver(@NotNull Canvas c, @NotNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                                float dX, float dY, int actionState, boolean isCurrentlyActive) {
        super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            View itemView = viewHolder.itemView;

            c.save();
            if (dX > 0) {
                c.clipRect(itemView.getLeft(), itemView.getTop(),
                        itemView.getLeft() + dX, itemView.getBottom());
                c.translate(itemView.getLeft(), itemView.getTop());
            } else {
                c.clipRect(itemView.getRight() + dX, itemView.getTop(),
                        itemView.getRight(), itemView.getBottom());
                c.translate(itemView.getRight() + dX, itemView.getTop());
            }

            mAdapter.onItemSwiping(c, viewHolder, dX, dY, isCurrentlyActive);
            c.restore();
        }
    }

}

使用

//拖动or滑动事件回调
val baseItemTouchHelpCallback = BaseItemTouchHelpCallback(mAdapter)
val itemTouchHelper = ItemTouchHelper(baseItemTouchHelpCallback)
itemTouchHelper.attachToRecyclerView(recyclerView)

//开启item拖拽
mAdapter.enableDragItem(itemTouchHelper)

//开启item中子view的拖拽,开启后textView将被占用
//mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true);

//拖拽回调事件,非必要
//mAdapter.setOnItemDragListener(onItemDragListener);

// 开启滑动删除
mAdapter.enableSwipeItem();

//滑动回调事件,非必要
//mAdapter.setOnItemSwipeListener(onItemSwipeListener);

你可能感兴趣的:(安卓基础)