RecycleView拖动效果

前言:基于RecycleView实现拖动效果,其实很简单,只需使用系统提供的ItemTouchHelper即可满足大部分需求。

实现:

1、创建ItemTouchHelper,在CallBack中处理业务

(1)getMovementFlags()设置允许拖动、滑动的方向

(2)onMove()拖动过程不断调用,用于交换item

(3)onSelectedChanged()长按选中回调,可以用作选中背景高亮

(4)clearView()结束拖动回调,可以用作还原选中背景

2、关联RecycleView,赋予滑动能力

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val tableList = ArrayList<String>()
        for (i in 1..200) {
            tableList.add("桌(${i})")
        }
        rv_table.layoutManager = GridLayoutManager(this, 5)
        TableAdapter().let {
            it.mTableList = tableList
            rv_table.adapter = it
        }
        val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
            override fun getMovementFlags(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder
            ): Int {
                //拖动方向
                val dargFlags =
                    ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
                //滑动方向
                val swipeFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
                //设置拖动、滑动方向
                return makeMovementFlags(dargFlags, swipeFlags)
            }

            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                //拖动的ViewHolder位置
                val fromPosition = viewHolder.adapterPosition
                //经过的ViewHolder位置
                val toPosition = target.adapterPosition
                when{
                    fromPosition < toPosition -> {//向后拖动,和位置+1进行交换
                        for (i in fromPosition..toPosition) {
                            Collections.swap(tableList, i, i + 1)
                        }
                        recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
                    }
                    fromPosition > toPosition -> {//向前拖动,和位置-1进行交换
                        for (i in fromPosition..toPosition) {
                            Collections.swap(tableList, i, i - 1)
                        }
                        recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
                    }
                }
                return true
            }

            override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
                super.onSelectedChanged(viewHolder, actionState)
                //长按选中更新要拖动的ViewHolder背景色
                (viewHolder as? TableAdapter.TableViewHolder)?.tvTabe?.setBackgroundResource(R.color.colorPrimary)
            }

            override fun clearView(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder
            ) {
                super.clearView(recyclerView, viewHolder)
                (viewHolder as TableAdapter.TableViewHolder).tvTabe.setBackgroundResource(R.color.colorAccent)
            }
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
        })
        //赋予RecycleView拖动能力
        itemTouchHelper.attachToRecyclerView(rv_table)
    }

进阶

场景一:禁止部分item拖动(如第1项禁止拖动)

1、禁用默认的拖动:CallBack中isLongPressDragEnabled()返回false

2、在自定义实现的item长按事件里,对于满足条件的执行拖动操作

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val tableList = ArrayList<String>()
        for (i in 1..200) {
            tableList.add("桌(${i})")
        }
        rv_table.layoutManager = GridLayoutManager(this, 5)
        val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
            override fun getMovementFlags(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder
            ): Int {
                //拖动方向
                val dargFlags =
                    ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
                //滑动方向
                val swipeFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
                //设置拖动、滑动方向
                return makeMovementFlags(dargFlags, swipeFlags)
            }

            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                //拖动的ViewHolder位置
                val fromPosition = viewHolder.adapterPosition
                //经过的ViewHolder位置
                val toPosition = target.adapterPosition
                when{
                    fromPosition < toPosition -> {//向后拖动,和位置+1进行交换
                        for (i in fromPosition..toPosition) {
                            Collections.swap(tableList, i, i + 1)
                        }
                        recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
                    }
                    fromPosition > toPosition -> {//向前拖动,和位置-1进行交换
                        for (i in fromPosition..toPosition) {
                            Collections.swap(tableList, i, i - 1)
                        }
                        recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
                    }
                }
                return true
            }

            override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
                super.onSelectedChanged(viewHolder, actionState)
                //长按选中更新要拖动的ViewHolder背景色
                (viewHolder as? TableAdapter.TableViewHolder)?.tvTabe?.setBackgroundResource(R.color.colorPrimary)
            }

            override fun clearView(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder
            ) {
                super.clearView(recyclerView, viewHolder)
                (viewHolder as TableAdapter.TableViewHolder).tvTabe.setBackgroundResource(R.color.colorAccent)
            }

            override fun isLongPressDragEnabled(): Boolean {
                //禁用默认拖动
                return false
            }
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
        })
        //赋予RecycleView滑动能力
        itemTouchHelper.attachToRecyclerView(rv_table)
        TableAdapter().let {
            it.mTableList = tableList
            rv_table.adapter = it
            //将拖动职能传递给Adapter
            it.mItemTouchHelper = itemTouchHelper
        }
    }

class TableAdapter : RecyclerView.Adapter<TableAdapter.TableViewHolder>(){
    var mTableList = ArrayList<String>()
    var mItemTouchHelper: ItemTouchHelper? = null

    override fun getItemCount(): Int {
        return mTableList.size
    }

    override fun onBindViewHolder(holder: TableViewHolder, position: Int) {
        val table = mTableList[position]
        holder.tvTabe.text = table
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TableViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_table, parent, false)
        return TableViewHolder(view)
    }

    inner class TableViewHolder constructor(view: View): RecyclerView.ViewHolder(view) {
        val tvTabe = view.findViewById<TextView>(R.id.tv_table)

        init {
            tvTabe.setOnLongClickListener {
                if (this.adapterPosition != 0){
                    mItemTouchHelper?.startDrag(this)
                    return@setOnLongClickListener true
                }
                return@setOnLongClickListener false
            }
        }
    }
}

场景二:只需将拖动的item和最终位置item进行交换,途径位置保持不变

1、在onMove()中将经过的位置记录到拖动的ViewHolder中

2、在clearView()中进行位置交换

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val tableList = ArrayList<String>()
        for (i in 1..200) {
            tableList.add("桌(${i})")
        }
        rv_table.layoutManager = GridLayoutManager(this, 5)
        val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
            override fun getMovementFlags(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder
            ): Int {
                //拖动方向
                val dargFlags =
                    ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
                //滑动方向
                val swipeFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
                //设置拖动、滑动方向
                return makeMovementFlags(dargFlags, swipeFlags)
            }

            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                //经过的ViewHolder位置保存到拖动的ViewHolder中
                val toPosition = target.adapterPosition
                (viewHolder as TableAdapter.TableViewHolder).toPosition = toPosition
                return true
            }

            override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
                super.onSelectedChanged(viewHolder, actionState)
                //长按选中更新要拖动的ViewHolder背景色
                (viewHolder as? TableAdapter.TableViewHolder)?.tvTabe?.setBackgroundResource(R.color.colorPrimary)
            }

            override fun clearView(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder
            ) {
                super.clearView(recyclerView, viewHolder)
                (viewHolder as TableAdapter.TableViewHolder).tvTabe.setBackgroundResource(R.color.colorAccent)
                //拖动ViewHolder位置
                val fromPosition = viewHolder.adapterPosition
                //终点位置
                val toPosition = viewHolder.toPosition
                if (toPosition >= 0){
                    Collections.swap(tableList, fromPosition, toPosition)
                    recyclerView.adapter?.let{
                        it.notifyItemChanged(fromPosition)
                        it.notifyItemChanged(toPosition)
                    }
                }
            }

            override fun isLongPressDragEnabled(): Boolean {
                //禁用默认拖动
                return false
            }
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
        })
        //赋予RecycleView滑动能力
        itemTouchHelper.attachToRecyclerView(rv_table)
        TableAdapter().let {
            it.mTableList = tableList
            rv_table.adapter = it
            //将拖动职能传递给Adapter
            it.mItemTouchHelper = itemTouchHelper
        }
    }
class TableAdapter : RecyclerView.Adapter<TableAdapter.TableViewHolder>(){
    var mTableList = ArrayList<String>()
    var mItemTouchHelper: ItemTouchHelper? = null

    override fun getItemCount(): Int {
        return mTableList.size
    }

    override fun onBindViewHolder(holder: TableViewHolder, position: Int) {
        val table = mTableList[position]
        holder.tvTabe.text = table
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TableViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_table, parent, false)
        return TableViewHolder(view)
    }

    inner class TableViewHolder constructor(view: View): RecyclerView.ViewHolder(view) {
        val tvTabe = view.findViewById<TextView>(R.id.tv_table)
        var toPosition = -1

        init {
            tvTabe.setOnLongClickListener {
                if (this.adapterPosition != 0){
                    mItemTouchHelper?.startDrag(this)
                    return@setOnLongClickListener true
                }
                return@setOnLongClickListener false
            }
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值