RecyclerView系列之侧滑删除和拖拽排序

一、背景
前面已经实现了 RecyclerView 的上拉加载更多,增加 header,自定义滑动菜单,基本能满足大部分场景的样式了,就算不满足也能通过直接改部分代码轻松实现新的样式;不过这一次产品玩别的 app 时发现了一个新的交互方式,某些列表不需要复杂的操作,只需要删除操作,那么如果用那种滑动菜单的交互方式,用户就得先把菜单滑出来,再点删除按钮才能删掉,这样一来用户就多操作了一步,不如直接让用户滑动删除,他说这叫返璞归真,简约效率。
在这里插入图片描述
二、思路分析
第一想法是通过修改之前的滑动菜单逻辑实现,打算修改一下边界,再控制一下状态判定阀值,但是总感觉这样搞不太合适,感觉有更简洁干脆的方法来实现这个,去网上看了一圈果然发现api里有个现成的工具类是专门来搞这类需求的,ItemTouchHelper。因为用的是现成的原生api,所以此文是对其一些用法的记录。那么这也不需要啥思路了,因为可以直接自定义一个类继承 ItemTouchHelper.Callback,然后可以直接通过监听 onSwiped 来实现滑动删除,另外在看这个类的监听时发现还有个onMove() 方法,这个太适合做拖拽排序了,所以干脆把排序的做法也记录一下。

三、具体实现
1.首先自定义一个类继承 ItemTouchHelper.Callback,通过实现 onSwiped 方法来监听滑动的操作,在此方法里执行实际删除列表 item 的逻辑;通过实现 onMove 方法来监听拖拽换位结果,在此方法里执行实际排序 item 的逻辑;

...    
    /**
     * 返回拖拽中换位的回调
     *
     * @param recyclerView
     * @param viewHolder
     * @param target
     * @return true:换位成功
     * false:没换成功
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
   
        if (null == onItemTouchHelperCallBack) {
   
            return false;
        }
        return onItemTouchHelperCallBack.onMove(viewHolder, target);
    }

    /**
     * 滑动后的回调
     *
     * @param viewHolder
     * @param direction
     */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
   
        if (null != onItemTouchHelperCallBack) {
   
            onItemTouchHelperCallBack.onSwiped(viewHolder);
        }
    }
...

在 RecyclerView的adapter 里实现这两个方法:

...
    @Override
    public boolean onMove(RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
   
        int adapterPosition = viewHolder.getAdapterPosition();
        int adapterPosition1 = target.getAdapterPosition();
        if (adapterPosition1 <= 2) {
   //例如设置position小于2的item不让换
            return false;
        }
        if (getHeaderViewCount() > 0) {
   
            Collections.swap(mDatas, adapterPosition - 1, adapterPosition1 - 1);
        } else {
   
            Collections.swap(mDatas, adapterPosition, adapterPosition1);
        }
        notifyItemMoved(adapterPosition, adapterPosition1);
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder) {
   
        int adapterPosition = viewHolder.getAdapterPosition();
        mDatas.remove(getHeaderViewCount() > 0 ? adapterPosition - 1 : adapterPosition);
        notifyItemRemoved(adapterPosition);
    }
...

然后在自定义的 Callback 类里设置一下允许滑动的参数:

    /**
     * 设置允许拖动换位和滑动删除的方向
     *
     * @param recyclerView
     * @param viewHolder
     * @return
     */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
   
        if (isContentType(viewHolder)) {
   
            //dragFlags:设置为可以向上和向下拖动
            //swipeFlags:设置成可以从左向右滑动删除
            return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.END);
        }
        return makeMovementFlags(0, 0);
    }

    private boolean isContentType(RecyclerView.ViewHolder viewHolder) {
   
        return viewHolder.getItemViewType() == BaseAdapter.TYPE_CONTENT_VIEW;
    }

这里需要注意的是要控制一下 header 和 footer 不能参与滑动删除和排序。
这样就实现了滑动删除和拖拽排序,这也太简单了,突然就实现了这个需求。这时产品设计上可能会有一些美化,例如滑动时要在 item 下面提示用户这是删除操作,这个可以通过实现 onChildDraw 方法,用 canvas 来画一些东西,例如在item后面显示 “delete” 文字提示用户:

    /**
     * 拖拽或滑动删除时,在item下面画点什么时用到
     */
    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
   
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        View itemView = viewHolder.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值