Tag Archives: Recyclerview drag

Inconsistency between adapter data and UI data after dragging recyclerview (data disorder)

Firstly, the function of dragging and sliding is added on the basis of recyclerview. It is written directly according to the official document as follows

 ItemTouchHelper(object : ItemTouchHelper.Callback() {
            override fun getMovementFlags(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
            ): Int {
                //item dragging direction
                var dragflag =
                    ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
                return makeMovementFlags(dragflag, 0)
            }

            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder,
            ): Boolean {
                myAdapter.notifyItemMoved(viewHolder.layoutPosition, target.layoutPosition)
                return true
            }


            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}

            override fun canDropOver(
                recyclerView: RecyclerView,
                current: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder,
            ): Boolean {
                //The current ViewHolder can be placed on the target ViewHolder
                return true
            }

            override fun isLongPressDragEnabled(): Boolean {
                //Turn on long press drag
                return true
            }

        }).attachToRecyclerView(binding.myRV)//add to RecyclerView

After running, it is found that the UI is normal, but when obtaining adapter.items, it is found that the data has not changed, so perform data exchange and sorting in onmove:

ItemTouchHelper(object : ItemTouchHelper.Callback() {
            override fun getMovementFlags(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
            ): Int {
                var dragflag =
                    ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
                return makeMovementFlags(dragflag, 0)
            }

            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder,
            ): Boolean {
                if (viewHolder.layoutPosition < target.layoutPosition) {
                    for (i in viewHolder.layoutPosition until target.layoutPosition) {
                        Collections.swap(myAdapter.items, i, i + 1) 
                    }
                } else {
                    for (i in viewHolder.layoutPosition downTo target.layoutPosition + 1) {
                        Collections.swap(myAdapter.items, i, i - 1) 
                    }

                }
                myAdapter.notifyItemMoved(viewHolder.layoutPosition, target.layoutPosition)
                myAdapter.notifyItemChanged(target.layoutPosition)
                return true
            }


            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}

            override fun canDropOver(
                recyclerView: RecyclerView,
                current: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder,
            ): Boolean {
                return true
            }

            override fun isLongPressDragEnabled(): Boolean {
                return true
            }

        }).attachToRecyclerView(binding.myRV)

If you want to listen to the end of drag, you can override the Clearview method to listen