[技术博客] 通过ItemTouchHelper实现侧滑删除功能

Posted boming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[技术博客] 通过ItemTouchHelper实现侧滑删除功能相关的知识,希望对你有一定的参考价值。

通过ItemTouchHelper实现侧滑删除功能

一、效果

技术图片

二、具体实现

demo中演示的这种左滑删除的效果在手机APP中比较常用,安卓也为我们提供了专门的辅助类ItemTouchHelper来帮助我们实现这个功能。ItemTouchHelper是一个工具类,可实现侧滑删除和拖拽移动,使用这个工具类需要RecyclerView和Callback。同时根据需要重写onMove和onSwiped方法。接下来就来讲述ItemTouchHelper的使用方法。
具体代码实现如下:

1、新建接口

从解耦的角度考虑,我们需要一个接口来实现Adapter和ItemTouchHelper之间涉及数据的操作,因为ItemTouchHelper在完成触摸的各种动画后,就要对Adapter的数据进行操作,比如侧滑删除操作。因此我们可以把数据操作的部分抽象成一个接口方法,让ItemTouchHelper.Callback调用该方法即可。

public interface ItemTouchHelperAdapter {
    public void onItemDelete(int position);//用来删除数据
    public void onItemRefresh(int position);//当用户误操作时用来恢复数据
}

2、在RecyclerView的Adapter类中实现接口中的两个方法

这里为了让大家看的清除把整个类都放上来了,其中只有下面两个方法是接口中的,其他的方法是为了给RecyclerView传递数据,详情可参考RecyclerView的使用方法。

public void onItemDelete(int position);
public void onItemRefresh(int position);

下面是demo中的我的收藏部分源码

public class MyCollectionAdapter extends RecyclerView.Adapter<MyCollectionAdapter.innerHolder> implements ItemTouchHelperAdapter {
    private final ArrayList<ItemCollection> mData;
    private MyCollectionAdapter.OnItemClickListener clickListener;

    public MyCollectionAdapter(ArrayList<ItemCollection> data){
        this.mData = data;
    }

    @NonNull
    @Override
    //创建条目View
    public MyCollectionAdapter.innerHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = View.inflate(parent.getContext(), R.layout.user_item_collection,null);
        return new MyCollectionAdapter.innerHolder(view);
    }

    @Override
    //用来绑定holder,设置数据
    public void onBindViewHolder(@NonNull MyCollectionAdapter.innerHolder holder, int position) {
        holder.setData(mData.get(position),position);
    }

    @Override
    //返回Item的个数
    public int getItemCount() {
        if(mData != null){
            return mData.size();
        }
        return 0;
    }

    public void setOnItemClickListener(MyCollectionAdapter.OnItemClickListener listener) {
        //设置一个Item的监听器
        clickListener = listener;
    }

    @Override
    public void onItemDelete(int position) {//删除数据操作,即用户点击确定删除时的逻辑
        ItemCollection del = mData.get(position);
        String url = "https://api.cnblogs.com/api/bookmarks/" + del.Id;
        DeleteApi delapi = new DeleteApi();
        @SuppressLint("HandlerLeak")
        final Handler handler = new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                if(msg.what == 1){
                    //删除成功
                    System.out.println("成功删除");
                }
            }
        };
        delapi.Delete(handler, url,1);//以上是API的调用删除网络数据部分
        mData.remove(position);//在本地ItemList中删除要删除的Item数据
        notifyItemRemoved(position);//提醒RecyclerView,使得后面的数据都向上移动一位
    }

    @Override
    public void onItemRefresh(int position) {//恢复数据,即用户点击取消时的逻辑
        notifyItemChanged(position);
    }

    public interface OnItemClickListener {//设置点击操作
        void OnItemClick(int position);
    }

    public class innerHolder extends RecyclerView.ViewHolder {//用来设置list数据
        private TextView title;
        private TextView Abstract;
        private TextView time;
        private int mPosition;

        public innerHolder(@NonNull View itemView) {
            super(itemView);
            title = itemView.findViewById(R.id.item_Collection_blogtitle);
            Abstract = itemView.findViewById(R.id.item_Collection_abstract);
            time = itemView.findViewById(R.id.item_Collection_time);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (clickListener != null) {
                        clickListener.OnItemClick(mPosition);
                    }
                }
            });
        }
        public void setData(ItemCollection itembean,int position){
            this.mPosition = position;
            title.setText(itembean.title);
            Abstract.setText(itembean.Abstract);
            time.setText(itembean.time);
        }
    }
}

3、新建类继承自ItemTouchHelper.Callback并重写方法

从官方文档我们知道,使用ItemTouchHelper需要一个Callback,该Callback是ItemTouchHelper.Callback的子类,所以我们需要新建一个类比如myItemTouchHelperCallBack继承自ItemTouchHelper.Callback。我们可以重写其数个方法来实现我们的需求。下面介绍demo中用到的方法。

public int getMovementFlags(RecyclerView, RecyclerView.ViewHolder)

该方法用于返回可以滑动的方向,比如说允许从右到左侧滑,允许上下拖动等。
在本demo中,我们允许Item上下拖动以及从右向左滑,代码如下:

public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        //允许上下拖动
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        //允许从右向左滑动
        int swipeFlags = ItemTouchHelper.LEFT;
        return makeMovementFlags(dragFlags,swipeFlags);
    }

public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)

当用户拖动一个Item进行上下移动从旧的位置到新的位置的时候会调用该方法,在我们的实例中是禁止这种操作的。

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

public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)

当用户左右滑动Item达到删除条件时,会调用该方法,一般手指触摸滑动的距离达到RecyclerView宽度的一半时,再松开手指,此时该Item会继续向原先滑动方向滑过去并且调用onSwiped方法进行删除,否则会反向滑回原来的位置。

public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        //onItemDelete接口里的方法
        showCoverDialog(viewHolder);
    }

private void showCoverDialog(final RecyclerView.ViewHolder viewHolder){//跳出提示窗口
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("提示");
        builder.setMessage(title);
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {//点击确定时,删除数据
                itemTouchHelperAdapter.onItemDelete(viewHolder.getAdapterPosition());
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {//点击取消时恢复Item
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                itemTouchHelperAdapter.onItemRefresh(viewHolder.getAdapterPosition());
            }
        });
        builder.show();
    }

public boolean isLongPressDragEnabled()

该方法返回true时,表示支持长按拖动,即长按ItemView后才可以拖动,由于默认是true,这里要改为false

public boolean isLongPressDragEnabled() {
        //该方法返回值为true时,表示支持长按ItemView拖动
        return false;
    }

public boolean boolean isItemViewSwipeEnabled()

该方法返回true时,表示如果用户触摸并左右滑动了View,那么可以执行滑动删除操作,即可以调用到onSwiped()方法。默认是true,为了看起来清除,我们也把这个方法写上

public boolean isItemViewSwipeEnabled() {
        //该方法返回true时,表示如果用户触摸并且左滑了view,那么可以执行滑动删除操作,就是可以调用onSwiped()方法
        return true;
    }

源代码如下

public class myItemTouchHelperCallBack extends ItemTouchHelper.Callback{
    private ItemTouchHelperAdapter itemTouchHelperAdapter;
    private Context context;
    private String title;

    public myItemTouchHelperCallBack(ItemTouchHelperAdapter itemTouchHelperAdapter, Context context, String title) {
        this.itemTouchHelperAdapter = itemTouchHelperAdapter;
        this.context = context;
        this.title = title;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        //允许上下拖动
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        //允许从右向左滑动
        int swipeFlags = ItemTouchHelper.LEFT;
        return makeMovementFlags(dragFlags,swipeFlags);
    }

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

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        //onItemDelete接口里的方法
        showCoverDialog(viewHolder);
    }

    @Override
    public boolean isLongPressDragEnabled() {
        //该方法返回值为true时,表示支持长按ItemView拖动
        return false;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        //该方法返回true时,表示如果用户触摸并且左滑了view,那么可以执行滑动删除操作,就是可以调用onSwiped()方法
        return true;
    }

    private void showCoverDialog(final RecyclerView.ViewHolder viewHolder){
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("提示");
        builder.setMessage(title);
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                itemTouchHelperAdapter.onItemDelete(viewHolder.getAdapterPosition());
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                itemTouchHelperAdapter.onItemRefresh(viewHolder.getAdapterPosition());
            }
        });
        builder.show();
    }
}

4、在RecycleView中添加ItemTouchHelper

ItemTouchHelper.Callback callback = new myItemTouchHelperCallBack(adapter,context,"确定删除此这篇收藏吗?");
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(myCollectionList);

自此我们就实现了左滑删除功能。
整个工程的代码在github上可以查看




以上是关于[技术博客] 通过ItemTouchHelper实现侧滑删除功能的主要内容,如果未能解决你的问题,请参考以下文章

类似支付宝应用管理界面——RecycleView+ItemTouchHelper实现拖拽滑动

Android开发 在不使用ItemTouchHelper的情况下实现ItemView的左右滑动

RecyclerView通过itemTouchHelper拖放快速拖动时很奇怪

RecyclerView 知识梳理 - ItemTouchHelper

五行代码实现 炫动滑动 卡片层叠布局,仿探探人人影视订阅界面 简单&优雅:LayoutManager+ItemTouchHelper

Android 事件分发ItemTouchHelper 事件分发源码分析 ( 绑定 RecyclerView )