Skip to content

Order issue when used along with swiping #111

@aj3423

Description

@aj3423

Thank you for this library.

I'm trying to migrate from v2.3.3 to v3. The v2.3.3 works all fine, but in v3, when the item is both reorderable and swipable, the modifier order is crucial.

For example, this works:

modifier = Modifier
	.draggableHandle()
	.anchoredDraggable(
		...
	)
	...

But this doesn't work, it's reorderable but not swipable

modifier = Modifier
	.anchoredDraggable(
		...
	)
	.draggableHandle()
	...

And if a swipable item is wrapped by a reorderable item, it also becomes unwipable:

Card(
	modifier = Modifier
		.anchoredDraggable(
			...
		)
) {
	Text(
		"...",
		modifier = Modifier
			.draggableHandle()
			...
	)
}

Here's a full demo:

@file:OptIn(ExperimentalFoundationApi::class)

package test.app

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.AnchoredDraggableState
import androidx.compose.foundation.gestures.DraggableAnchors
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.anchoredDraggable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import sh.calvin.reorderable.ReorderableColumn
import kotlin.math.roundToInt

data class Item(
    val id: Int
)

private const val SwipeDistanceDp = 100

enum class Anchor { Left, Center, Right }

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            val itemList = remember { mutableStateListOf<Item>() }
            itemList.add(Item(1))
            itemList.add(Item(2))
            itemList.add(Item(3))

            ReorderableColumn(
                list = itemList,
                modifier = Modifier.padding(start = 100.dp, top = 200.dp),
                onSettle = { fromIndex, toIndex ->
                    itemList.apply {
                        add(toIndex, removeAt(fromIndex))
                    }
                },
                verticalArrangement = Arrangement.spacedBy(4.dp)
            ) { index, item, isDragging ->

                key(item.id) {
                    ReorderableItem {

                        val density = LocalDensity.current

                        val openOffsetPx = with(density) { SwipeDistanceDp.dp.toPx() }

                        val anchors = remember(density) {
                            DraggableAnchors {
                                Anchor.Center at 0f
                                Anchor.Left at -openOffsetPx
                                Anchor.Right at openOffsetPx
                            }
                        }

                        val state = remember {
                            AnchoredDraggableState(
                                initialValue = Anchor.Center,
                                anchors = anchors,
                            )
                        }
                        SideEffect {
                            state.updateAnchors(anchors)
                        }


                        Text(
                            "Swipe me, it works ${item.id}",
                            modifier = Modifier
                                .padding(vertical = 10.dp)

                                .draggableHandle()
                                .anchoredDraggable(
                                    state = state,
                                    orientation = Orientation.Horizontal,
                                )

                                .offset {
                                    IntOffset(
                                        x = state.requireOffset().roundToInt(),
                                        y = 0
                                    )
                                }
                        )

                        // This doesn't work
//                        Text(
//                            "Swipe me, it doesn't work ${item.id}",
//                            modifier = Modifier
//                                .padding(vertical = 10.dp)
//
//                                .anchoredDraggable(
//                                    state = state,
//                                    orientation = Orientation.Horizontal,
//                                )
//                                .draggableHandle()
//
//                                .offset {
//                                    IntOffset(
//                                        x = state.requireOffset().roundToInt(),
//                                        y = 0
//                                    )
//                                }
//                        )

                        //  also doesn't work when wrappen in a `anchoredDraggable`
//                        Card(
//                            modifier = Modifier.anchoredDraggable(
//                                state = state,
//                                orientation = Orientation.Horizontal,
//                            )
//                        ) {
//                            Text(
//                                "Swipe me, it doesn't work either ${item.id}",
//                                modifier = Modifier
//                                    .padding(vertical = 10.dp)
//
//                                    .draggableHandle()
//
//                                    .offset {
//                                        IntOffset(
//                                            x = state.requireOffset().roundToInt(),
//                                            y = 0
//                                        )
//                                    }
//                            )
//                        }
                    }
                }
            }
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions