概述

列表数据显示越来越多的使用RecyclerView来实现,借助ItemTouchHelper实现长按拖动,滑动删除也更加方便

简单实现

ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(mView.rvDesktopAppsort);

简单实现只能达到效果,但实际的数据处理并未发生变化,需要自定义Callback来实现,简单实现也要new一个Callback出来

自定义Callback

定义一个接口来回调Adapter中绑定的具体事件

public interface ITouchHelperAdapter {
    //Item长按拖动事件
    void onItemMove(int fromPosition, int toPosition);
    //滑动删除后清理事件
    void onItemSwip(int position);
    //是否允许滑动删除
    boolean canSwip();
}

自定义 SimpleTouchHelperCallback

重点重写几个方法

  • getMovementFlags # 设置滑动和拖动的方向
  • onMove # 长按拖动事件
  • onSwiped # 滑动删除事件

如果需要控制是否允许滑动删除,还要重写一个方法

  • isItemViewSwipeEnabled # 通过返回true或false来控制是否允许滑动删除

在Callback中构造函数中传入继承了上面接口的Adapter以取得具体回调事件

public class SimpleTouchHelperCallback extends ItemTouchHelper.Callback {
    private final ITouchHelperAdapter adapter;
    public SimpleTouchHelperCallback(ITouchHelperAdapter adapter) {
        this.adapter = adapter;
    }
	//定义长按拖动和滑动的方向,返回0表示禁止滑动
    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        //滑动方向,此处只开启右滑删除(END代表阅读习惯结束的方向)
        int swipFlag = ItemTouchHelper.END; 
        //长按拖动方向,上下左右都可拖动
        int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; 
        return makeMovementFlags(dragFlag, swipFlag);
    }
	//长按拖动事件,回调接口中的 onItemMove() 方法
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }
	//侧滑删除后的清理事件
    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        adapter.onItemSwip(viewHolder.getAdapterPosition());
    }
	//是否开启侧滑删除功能,在外部通过返回布尔值来达到控制
    @Override
    public boolean isItemViewSwipeEnabled() {
        return adapter.canSwip();
    }
	//是否开启长按拖动功能,返回true表示开启
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }
}

PS
目前无法在侧滑移除之前进行拦截,只能通过是否允许侧滑来控制是否删除。因为一旦调用了侧滑事件,UI上即已经移除了Item,如果不处理相应的Adapter移除动作,则会造成不同步。手动呼叫侧滑又没有相应的触发事件。
有解决方案的朋友望指教一二,先谢谢了。

Adapter中继承接口并实现具体方法内容

public class ReferItemAdapter extends RecyclerView.Adapter<ReferItemAdapter.viewHolder> implements ITouchHelperAdapter {
    //长按拖动时变更项目的索引位置,swap的方式是直接交换,此处采用拖动插入的方式执行    
    @Override
    public void onItemMove(int fromPosition, int toPosition) {
        //Collections.swap(lstItems, fromPosition, toPosition);
        ReferItemEntity referItem = lstItems.get(fromPosition);
        lstItems.remove(referItem);
        lstItems.add(toPosition, referItem);
        notifyItemMoved(fromPosition, toPosition);
    }
	//侧滑删除后从列表中移除item并通过adapter更新移除
    //先执行数据库删除否则position会因发生变化而删除错误
    @Override
    public void onItemSwip(int position) {
        itemRemoveListener.onRemove(position);
        lstItems.remove(position);
        notifyItemRemoved(position);
    }
    //通过返回true或false来控制是否允许侧滑删除
    @Override
    public boolean canSwip() {
        if(lstItems.get(0).getItem_type().equals("charge_tag")) return true;
        else return false;
    }
}

以上方法中定义了一个 itemRemoveListener 接口的回调 onRemove方法以便在Activity中执行数据库方面的删除操作

interface OnRVItemRemoveListener{
    void onRemove(int position);
}
private IAdapter.OnRVItemRemoveListener itemRemoveListener;
public void setItemRemoveListener(IAdapter.OnRVItemRemoveListener listener) {
    this.itemRemoveListener = listener;
}

Activity中通过 new IAdapter.OnRVItemRemoveListener() 的方式实现具体的 onRemove() 方法内容

因为实例化Adapter时传入的是List<>列表对象,内外列表指向同一堆上地址,所以内外变更时列表会同步更新

referItemAdapter.setItemRemoveListener(position -> {
    //通知Presenter执行数据库删除
    mPresenter.itemDelete(lstItems.get(position));
});