android / views-widgets-samples

Multiple samples showing the best practices in views-widgets on Android.
Apache License 2.0
5.03k stars 3.01k forks source link

Drag and drop issue with RecyclerView, ItemTouchHelper and GridLayoutManager #219

Open hjudez opened 3 years ago

hjudez commented 3 years ago

I have found an issue when dragging an item that doesn't trigger a move on a GridLayoutManager with 2 columns. When dragging one item from the first column to the top of the list (which scrolls the list upwards) and then back to its original position, the recyclerView creates an empty space next to the original position, pushing the item that was next to the dragged item to the next row.

I can reproduce this issue using the simplest implementation:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val myAdapter = MyAdapter()
    with(findViewById<RecyclerView>(R.id.recyclerView)) {
        adapter = myAdapter
        layoutManager = GridLayoutManager(this@MainActivity, 2)
        ItemTouchHelper(object : ItemTouchHelper.Callback() {

            override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
                return makeFlag(ItemTouchHelper.ACTION_STATE_DRAG, DOWN or UP or START or END)
            }

            override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
                return false
            }

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

            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                TODO("Not yet implemented")
            }

        }).attachToRecyclerView(this)
    }
    myAdapter.submitList(data)
}

data class ListItem(val id: String, val name: String)

class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

}

class MyAdapter : ListAdapter<ListItem, MyViewHolder>(MyAdapterDiffCallback()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {

    }

    class MyAdapterDiffCallback : DiffUtil.ItemCallback<ListItem>() {
        override fun areItemsTheSame(oldItem: ListItem, newItem: ListItem) = oldItem.id == newItem.id

        override fun areContentsTheSame(oldItem: ListItem, newItem: ListItem) = oldItem == newItem
    }
}

8frNp

xm7uF

HUzJ0

rohittrimale commented 2 years ago

can i work on this issue