怎么简单实现菜单拖拽排序的功能

1、效果

在这里插入图片描述

2、简介

本文主角是ItemTouchHelper。
它是RecyclerView对于item交互处理的一个「辅助类」,主要用于拖拽以及滑动处理。
以接口实现的方式,达到配置简单、逻辑解耦、职责分明的效果,并且支持所有的布局方式。

3、功能拆解

在这里插入图片描述

4、功能实现

4.1、实现接口

自定义一个类,实现ItemTouchHelper.Callback接口,然后在实现方法中根据需求简单配置即可。

class DragCallBack(adapter: DragAdapter, data: MutableList<String>) : ItemTouchHelper.Callback() {
   
}
复制代码

ItemTouchHelper.Callback必须实现的3个方法:

  • getMovementFlags
  • onMove
  • onSwiped

其他方法还有onSelectedChanged、clearView等

4.1.1、getMovementFlags

用于创建交互方式,交互方式分为两种:

1.拖拽,网格布局支持上下左右,列表只支持上下(LEFT、UP、RIGHT、DOWN)
2.滑动,只支持前后(START、END)

最后,通过makeMovementFlags把结果返回回去,makeMovementFlags接收两个参数,dragFlags和swipeFlags,即上面拖拽和滑动组合的标志位。

 override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
   
        var dragFlags = 0
        var swipeFlags = 0
        when (recyclerView.layoutManager) {
   
            is GridLayoutManager -> {
   
                // 网格布局
                dragFlags = ItemTouchHelper.LEFT or ItemTouchHelper.UP or ItemTouchHelper.RIGHT or ItemTouchHelper.DOWN
                return makeMovementFlags(dragFlags, swipeFlags)
            }
            is LinearLayoutManager -> {
   
                // 线性布局
                dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
                swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
                return makeMovementFlags(dragFlags, swipeFlags)
            }
            else -> {
   
                // 其他情况可自行处理
                return 0
            }
        }
    }
复制代码

4.1.2、onMove

拖拽时回调,这里我们主要对起始位置和目标位置的item做一个数据交换,然后刷新视图显示。

   override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
   
        // 起始位置
        val fromPosition = viewHolder.adapterPosition
        // 结束位置
        val toPosition = target.adapterPosition
        // 固定位置
        if (fromPosition == mAdapter.fixedPosition || toPosition == mAdapter.fixedPosition) {
   
            return false
        }
        // 根据滑动方向 交换数据
        if (fromPosition < toPosition) {
   
            // 含头不含尾
            for (index in fromPosition until toPosition) {
   
                Collections.swap(mData, index, index + 1)
            }
        } else {
   
            // 含头不含尾
            for (index in fromPosition downTo toPosition + 1) {
   
                Collections.swap(mData, index, index - 1)
            }
        }
        // 刷新布局
        mAdapter.notifyItemMoved(fromPosition, toPosition)
        return true
    }
复制代码

4.1.3、onSwiped

滑动时回调,这个回调方法里主要是做数据和视图的更新操作。

   override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
   
        if (direction == ItemTouchHelper.START) {
   
            Log.i(TAG, "START--->向左滑")
        } else {
   
            Log.i(TAG, "END--->向右滑")
        }
        val position = viewHolder.adapterPosition
        mData.removeAt(position)
        mAdapter.notifyItemRemoved(position)
    }
复制代码

4.2、绑定RecyclerView

上面接口实现部分我们已经简单写好了,逻辑也挺简单,总共不超过100行代码。
接下来就是把这个辅助类绑定到RecyclerView。
RecyclerView显示的实现就是基础的样式,就不展开了,可以查看源码。

       val dragCallBack = DragCallBack(mAdapter, list)
        val itemTouchHelper = ItemTouchHelper(dragCallBack)
        itemTouchHelper.attachToRecyclerView(mBinding.recycleView)
复制代码

绑定只需要调用attachToRecyclerView就好了。
至此,简单的效果就已经实现了。下面开始优化和进阶的部分。

4.3、设置分割线

RecyclerView网格布局实现等分,我们一般先是自定义ItemDecoration,然后调用addItemDecoration来实现的。
但是我在实现效果的时候遇到一个问题,因为我加了布局切换的功能,在每次切换的时候,针对不同的布局分别设置layoutManager和ItemDecoration,这就导致随着切换次数的增加,item的间隔就越大。
addItemDecoration,顾名思义是添加,通过查看源码发现RecyclerView内部是有一个ArrayList来维护的,所以当我们重复调用addItemDecoration方法时,分割线是以递增的方式在增加的,并且在绘制的时候会从集合中遍历所有的分割线绘制。
部分源码:

  @Override
    public void draw(Canvas c) {
   
        super.draw(c);

        final int count = mItemDecorations.size();
        for (int i = 0; i < count; i++
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CRMEB定制开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值