利用 ItemTouchHelper 实现 RecyclerView 的侧滑删除

利用 ItemTouchHelper 可以实现 RecyclerView 的侧滑删除和滑动。
在官方文档的定义:
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

要实现 RecyclerView 的侧滑和滑动功能,需要继承 ItemTouchHelper.CallBack 接口,并实现相关方法。不过还好,官方已经为我们实现是一个默认的 CallBack, 叫 ItemTouchHelper.SimpleCallBack;

一、使用 ItemTouchHelper.SimpleCallBack

继承 ItemTouchHelper.SimpleCallBack 需要实现两个方法,
一个是 onMove(RecyclerView, ViewHolder, ViewHolder) ,这是移动时会回调的方法;
另一个是 onSwiped(ViewHolder, int),这是在滑动时的回调方法。
下面是示例代码:

public class SimpleTouchHelper extends ItemTouchHelper.SimpleCallback {

    private ItemTouchHelperAdapter mItemTouchHelperAdapter;

    public void setItemTouchHelperAdapter(ItemTouchHelperAdapter itemTouchHelperAdapter) {
        mItemTouchHelperAdapter = itemTouchHelperAdapter;
    }


    public SimpleTouchHelper(int dragDirs, int swipeDirs) {
        super(dragDirs, swipeDirs);
    }

    // 移动
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        // 移动开始的位置
        int formPosition = viewHolder.getAdapterPosition();
        //
        int toPosition = target.getAdapterPosition();
        mItemTouchHelperAdapter.onItemMove(formPosition, toPosition);
        return true;
    }

    // 滑动
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        int position = viewHolder.getAdapterPosition();
        mItemTouchHelperAdapter.onItemDismiss(position);
    }
}

其中 ItemTouchHelperAdapter 是回调接口

public interface ItemTouchHelperAdapter {

    void onItemMove(int fromPosition, int toPosition);

    void onItemDismiss(int position);
}

给 RecyclerView 设置 ItemTouchHelper

mSimpleTouchHelper = new SimpleTouchHelper(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
                                                                               ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT);
        mSimpleTouchHelper.setItemTouchHelperAdapter(new ItemTouchHelperAdapter() {
            @Override
            public void onItemMove(int fromPosition, int toPosition) {

                Log.i("swipe", "from position " + fromPosition + " to position " + toPosition);
                if (fromPosition < toPosition) {
                    for (int i = fromPosition; i < toPosition; i++) {
                        Collections.swap(mStringList, i, i + 1);
                    }
                } else {
                    for (int i = fromPosition; i > toPosition; i--) {
                        Collections.swap(mStringList, i, i - 1);
                    }
                }
                mAdapter.notifyItemMoved(fromPosition, toPosition);
            }

            @Override
            public void onItemDismiss(int position) {
                mStringList.remove(position);
                mAdapter.notifyItemRemoved(position);
                Toast.makeText(MainActivity.this, "删除 " + position,
                 Toast.LENGTH_SHORT).show();
            }
        });

        ItemTouchHelper itemTouchHelper = new  
                         ItemTouchHelper(mSimpleTouchHelper);
        itemTouchHelper.attachToRecyclerView(recycler_view);
  1. SimpleTouchHelper(int dragDirs, int swipDirs) 构造函数第一个参数是拖动的方法,这里是 UP 和 DOWN 方法,当我们将 item 向上或向下时会是拖动;第二参数是滑动,这里是 LEFT 和 RIGHT, 当将 item 左右时会是滑动。

  2. 将 SimpleTouchHelper 作为参数传进 ItemTouchHelper 的构造函数,生成 ItemTouchHelper 对象,然后调用 ItemTouchHelper#attachToRecyclerView(RecyclerView) 发放即可。

  3. 在 onItemMove(…) 回调中进行 Item 位置的交换,在 onItemMiss(…) 回调中删除 item.

效果图,滑动删除
这里写图片描述

效果图,拖动时
这里写图片描述

二、ItemTouchHelper.CallBack

如果是自定义一个 Touch Callback, 则需要监听拖动和滑动事件。
1.一般需要重写拖动回调 onMove(RecyclerView, ViewHolder, ViewHolder) 事件

   @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        // 开始位置
        int fromPosition = viewHolder.getAdapterPosition();
        // 拖动的目标位置
        int toPosition = target.getAdapterPosition();
        mAdapter.onItemMove(fromPosition, toPosition);
        // 返回 true, 开启移动
        return true;
    }
  1. 重写滑动回调方法 onSwiped(ViewHolder, direction)
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }
  1. 以及 getMovementFlags,onChildDraw 和 onSelectedChanged 方法。

以下是完整代码

public class CustomItemTouchCallBack extends ItemTouchHelper.Callback {

    public static final float ALPHA_FULL = 1.0f;

    private ItemTouchHelperAdapter mAdapter;

    public CustomItemTouchCallBack(ItemTouchHelperAdapter adapter) {
        mAdapter = adapter;
    }

    /**
     *   控制 行为,并返回一系列的 方向标志
     * @param recyclerView
     * @param viewHolder
     * @return
     */
    @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 onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        // 开始位置
        int fromPosition = viewHolder.getAdapterPosition();
        // 拖动的目标位置
        int toPosition = target.getAdapterPosition();
        mAdapter.onItemMove(fromPosition, toPosition);
        // 返回 true, 开启移动
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE){     // 滑动的时候
            // 当滑动的时候,item 淡出
            float alpha = ALPHA_FULL - Math.abs(dX) /  viewHolder.itemView.getWidth();
            viewHolder.itemView.setAlpha(alpha);
            viewHolder.itemView.setTranslationX(dX);
       } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    }

    /**
     * 选中时 item 的变化
     * @param viewHolder
     * @param actionState
     */
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE){  // 闲置状态
            if (viewHolder instanceof ItemTouchHelperViewHolder){
                ItemTouchHelperViewHolder itemTouchHelperViewHolder = (ItemTouchHelperViewHolder) viewHolder;
                itemTouchHelperViewHolder.onItemSelected();
            }
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    /**
     *  释放 item 之前设置的状态
     * @param recyclerView
     * @param viewHolder
     */
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);

        viewHolder.itemView.setAlpha(ALPHA_FULL);

        Log.i("itemTouch", "clear view");

        if (viewHolder instanceof ItemTouchHelperViewHolder){
            ItemTouchHelperViewHolder itemTouchHelperViewHolder = (ItemTouchHelperViewHolder) viewHolder;
            itemTouchHelperViewHolder.onItemClear();
        }
    }

    /**
     *  是否允许长按开始拖动
     *   我们这里开启
     * @return
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    /**
     *  是否选项 item 滑动
     *   我们这里开启
     * @return
     */
    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }
}

详情,看代码中的注释。

其中 ItemTouchHelperViewHolder 是接口, RecyclerView 中的 ViewHolder 需要实现它。

public interface ItemTouchHelperViewHolder {

    /**
     *  ViewHolder 中 Item 选中时回调
     */
    void onItemSelected();

    /**
     *  完成 移动或者滑动之后的回调,清除 View 的状态
     */
    void onItemClear();
}

在 RecyclerView#ViewHolder 中

public class ItemTouchAdapter extends  RecyclerView.Adapter<ItemTouchAdapter.VHolder> implements ItemTouchHelperAdapter{

    private Context mContext;
    private List<String> mStrings;

    public ItemTouchAdapter(Context context, List<String> strings) {
        mContext = context;
        mStrings = strings;
    }

    @Override
    public VHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_layout, parent, false);
        return new VHolder(view);
    }

    @Override
    public void onBindViewHolder(VHolder holder, int position) {
        holder.tv_item.setText(mStrings.get(position));
    }

    @Override
    public int getItemCount() {
        return mStrings.size();
    }

    @Override
    public void onItemMove(int fromPosition, int toPosition) {
        Log.i("swipe", "from position " + fromPosition + " to position " + toPosition);
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(mStrings, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(mStrings, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onItemDismiss(int position) {
        mStrings.remove(position);
        notifyItemRemoved(position);
    }


    static class  VHolder extends RecyclerView.ViewHolder implements  ItemTouchHelperViewHolder{

        TextView tv_item;

        public VHolder(View itemView) {
            super(itemView);

            tv_item = (TextView) itemView.findViewById(R.id.tv_item);
        }

        @Override
        public void onItemSelected() {
            itemView.setBackgroundColor(Color.LTGRAY);
        }

        @Override
        public void onItemClear() {
            Log.i("itemTouch","onItemClear");
            itemView.setBackgroundColor(Color.TRANSPARENT);
        }
    }
}

最后通过 ItemTouchHelper 设置到 RecyclerView 中

CustomItemTouchCallBack itemTouchCallBack = new CustomItemTouchCallBack(mAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallBack);
itemTouchHelper.attachToRecyclerView(recycler_view);

最后运行的结果与上面的两个图一样的。

从官方文档摘录关于继承 Callback 的几个事项
1. Listen for “move” and “swipe” events.

  1. Can control the state of the view selected, and override the default animations.

  2. To control which actions user can take on each view, override getMovementFlags(RecyclerView, ViewHolder, ViewHolder) and return appropriate set of direction flags(LEFT, RIGHT, START, END, UP, DOWN).

  3. Drag on item, call onMove(RecyclerView, dragged, target)
    move the item from the old position , dragged.getAdapterPosition() to new position, target.getAdapterPosition .
    Adapter call notifyItemMoved(int, int).

  4. When a view is swiped calls onSwiped(ViewHolder, int). At this point, update adapter(e.g remove the item) and call related Adapter#notify event.

注:

参考
1. Drag and Swipe with RecyclerView Part One: Basic ItemTouchHelper Example

2.Drag and Swipe with RecyclerView Part Two: Handles, Grids, and Custom Animations

3.Android ItemTouchHelper 实践

发布了58 篇原创文章 · 获赞 20 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/yxhuang2008/article/details/66550682