Search code examples
androidandroid-jetpack-compose

Reorder LazyColumn items with drag & drop


I want to create a LazyColumn with items that can be reordered by drag & drop. Without compose, my approach would be to use ItemTouchHelper.SimpleCallback, but I haven't found anything like that for compose.

I've tried using Modifier.longPressDragGestureFilter and Modifier.draggable, but that merely allows me to drag the card around using an offset. It doesn't give me a list index (like fromPosition/toPosition in ItemTouchHelper.SimpleCallback), which I need to swap the items in my list.

Is there a compose equivalent to ItemTouchHelper.SimpleCallback's onMove function? If not, is it a planned feature?

Is it possible/feasible to try and implement this sort of thing myself?


Solution

  • So far from what I can tell Compose doesn't offer a way of handling this yet, although I'm assuming this will be in the works as they have added the draggable and longPressDragGestureFilter modifiers as you have already mentioned. As they have added these in, maybe this is a precursor to drag and drop inside of lazy columns.

    A issue was raised with Google in Feb 2021, their response was there will be no official solution from them for the 1.0 release, although within this they have provided some guidance on how to approach the solution. It looks like the best solution for now is to have a RecyclerView with the ItemTouchHelper.

    Here is the issue mentioned: https://issuetracker.google.com/issues/181282427


    UPDATE 23/11/21

    Although this doesn't handle the clicks of the items themselves, it only handles the animation, this is a step towards a internal drag to reorder. They have added the option to use a new modifier called Modifier.animateItemPlacement() in combination with providing a key when setting the items up.

    https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.1.0-beta03

    Example:

    var list by remember { mutableStateOf(listOf("A", "B", "C")) }
    LazyColumn {
        item {
            Button(onClick = { list = list.shuffled() }) {
                Text("Shuffle")
            }
        }
        items(list, key = { it }) {
            Text("Item $it", Modifier.animateItemPlacement())
        }
    }