最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

kotlin - How to drag item in LazyColumn when drag - Stack Overflow

programmeradmin5浏览0评论

Making draggable items in LazyColumn. I have implemented the functionalities when drag after long press the IconButton. But what I want is drag immediately after start dragging. But simply changing detectDragGesturesAfterLongPress to detectDragGestures doesn't work.

@Composable
fun Screen2(modifier: Modifier = Modifier) {
    val density = LocalDensity.current

    val list = remember { mutableStateListOf(
        "Kotlin", "Java", "C++", "Python", "C", "Assembly"
    ) }
    var draggedItemIndex by remember { mutableIntStateOf(-1) }
    val heightDp = remember { 80.dp } // Height of an item
    val heightPx = remember { with(density) { heightDp.toPx() } }

    LazyColumn(
        modifier = modifier
    ) {
        itemsIndexed(list, key = { _, k -> k }) { index, text ->

            var dragOffsetY by remember { mutableFloatStateOf(0F) }
            var isDragged by remember { mutableStateOf(false) }

            Card(
                modifier = Modifier
                    .padding(8.dp)
                    .graphicsLayer {
                        translationY = dragOffsetY
                        shadowElevation = if (isDragged) 8F else 0F
                        alpha = if (isDragged) .9F else 1F
                    }
                    .zIndex(if (isDragged) 2F else 0F)
                    .fillMaxWidth()
                    .then(if (isDragged) Modifier else Modifier.animateItem())
            ) {
                Row(
                    modifier = Modifier
                        .padding(8.dp)
                        .fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text(text)

                    IconButton(
                        onClick = {},
                        modifier = Modifier
                            .pointerInput(index) {
                                detectDragGesturesAfterLongPress(
                                    onDragStart = {
                                        draggedItemIndex = index
                                        isDragged = true
                                    }
                                ) { _, _ -> }
                            }
                            .pointerInput(Unit) {
                                detectDragGesturesAfterLongPress(
                                    onDragEnd = {
                                        dragOffsetY = 0F
                                        draggedItemIndex = -1
                                        isDragged = false
                                    },
                                    onDragCancel = {
                                        dragOffsetY = 0F
                                        draggedItemIndex = -1
                                        isDragged = false
                                    }
                                ) { change, dragAmount ->
                                    change.consume()
                                    dragOffsetY += dragAmount.y

                                    val indexOffset = (dragOffsetY / heightPx).toInt()
                                    val newIndex = indexOffset + draggedItemIndex

                                    if (newIndex in list.indices && newIndex != draggedItemIndex) {
                                        Collections.swap(list, draggedItemIndex, newIndex)
                                        draggedItemIndex = newIndex
                                        dragOffsetY -= indexOffset * heightPx
                                    }
                                }
                            }
                    ) {
                        Icon(Icons.Default.DragHandle, "Drag Handle")
                    }
                }
            }

        }
    }
}

I am looking for solution such that an item should be able to drag immediately when drag from the IconButton.

Sample:

  1. First one is with detectDragGesturesAfterLongPress
  2. Second one is with detectDragGestures

Making draggable items in LazyColumn. I have implemented the functionalities when drag after long press the IconButton. But what I want is drag immediately after start dragging. But simply changing detectDragGesturesAfterLongPress to detectDragGestures doesn't work.

@Composable
fun Screen2(modifier: Modifier = Modifier) {
    val density = LocalDensity.current

    val list = remember { mutableStateListOf(
        "Kotlin", "Java", "C++", "Python", "C", "Assembly"
    ) }
    var draggedItemIndex by remember { mutableIntStateOf(-1) }
    val heightDp = remember { 80.dp } // Height of an item
    val heightPx = remember { with(density) { heightDp.toPx() } }

    LazyColumn(
        modifier = modifier
    ) {
        itemsIndexed(list, key = { _, k -> k }) { index, text ->

            var dragOffsetY by remember { mutableFloatStateOf(0F) }
            var isDragged by remember { mutableStateOf(false) }

            Card(
                modifier = Modifier
                    .padding(8.dp)
                    .graphicsLayer {
                        translationY = dragOffsetY
                        shadowElevation = if (isDragged) 8F else 0F
                        alpha = if (isDragged) .9F else 1F
                    }
                    .zIndex(if (isDragged) 2F else 0F)
                    .fillMaxWidth()
                    .then(if (isDragged) Modifier else Modifier.animateItem())
            ) {
                Row(
                    modifier = Modifier
                        .padding(8.dp)
                        .fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text(text)

                    IconButton(
                        onClick = {},
                        modifier = Modifier
                            .pointerInput(index) {
                                detectDragGesturesAfterLongPress(
                                    onDragStart = {
                                        draggedItemIndex = index
                                        isDragged = true
                                    }
                                ) { _, _ -> }
                            }
                            .pointerInput(Unit) {
                                detectDragGesturesAfterLongPress(
                                    onDragEnd = {
                                        dragOffsetY = 0F
                                        draggedItemIndex = -1
                                        isDragged = false
                                    },
                                    onDragCancel = {
                                        dragOffsetY = 0F
                                        draggedItemIndex = -1
                                        isDragged = false
                                    }
                                ) { change, dragAmount ->
                                    change.consume()
                                    dragOffsetY += dragAmount.y

                                    val indexOffset = (dragOffsetY / heightPx).toInt()
                                    val newIndex = indexOffset + draggedItemIndex

                                    if (newIndex in list.indices && newIndex != draggedItemIndex) {
                                        Collections.swap(list, draggedItemIndex, newIndex)
                                        draggedItemIndex = newIndex
                                        dragOffsetY -= indexOffset * heightPx
                                    }
                                }
                            }
                    ) {
                        Icon(Icons.Default.DragHandle, "Drag Handle")
                    }
                }
            }

        }
    }
}

I am looking for solution such that an item should be able to drag immediately when drag from the IconButton.

Sample:

  1. First one is with detectDragGesturesAfterLongPress
  2. Second one is with detectDragGestures
Share Improve this question edited Mar 11 at 8:42 Surendra asked Mar 10 at 18:15 SurendraSurendra 236 bronze badges 2
  • Can you show your modified code that's using detectDragGestures – Edric Commented Mar 11 at 1:22
  • I have edited the question with relevant samples. – Surendra Commented Mar 11 at 8:44
Add a comment  | 

2 Answers 2

Reset to default 0

With your code I was able to try something like this:

@Composable
fun Screen2(modifier: Modifier = Modifier) {
    val density = LocalDensity.current

    val list = remember { mutableStateListOf(
        "Kotlin", "Java", "C++", "Python", "C", "Assembly"
    ) }
    var draggedItemIndex by remember { mutableIntStateOf(-1) }
    val heightDp = remember { 80.dp }
    val heightPx = remember { with(density) { heightDp.toPx() } }

    LazyColumn(
        modifier = modifier
    ) {
        itemsIndexed(list, key = { _, k -> k }) { index, text ->

            var dragOffsetY by remember { mutableFloatStateOf(0F) }
            var isDragged by remember { mutableStateOf(false) }

            Card(
                modifier = Modifier
                    .padding(8.dp)
                    .graphicsLayer {
                        translationY = dragOffsetY
                        shadowElevation = if (isDragged) 8F else 0F
                        alpha = if (isDragged) .9F else 1F
                    }
                    .zIndex(if (isDragged) 2F else 0F)
                    .fillMaxWidth()
            ) {
                Row(
                    modifier = Modifier
                        .padding(8.dp)
                        .fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text(text)

                    IconButton(
                        onClick = {},
                        modifier = Modifier
                            .pointerInput(Unit) {
                                detectDragGestures(
                                    onDragStart = { offset ->
                                        draggedItemIndex = index
                                        isDragged = true
                                    },
                                    onDrag = { change, dragAmount ->
                                        change.consume()
                                        dragOffsetY += dragAmount.y

                                        val indexOffset = (dragOffsetY / heightPx).toInt()
                                        val newIndex = indexOffset + draggedItemIndex

                                        if (newIndex in list.indices && newIndex != draggedItemIndex) {
                                            Collections.swap(list, draggedItemIndex, newIndex)
                                            draggedItemIndex = newIndex
                                            dragOffsetY -= indexOffset * heightPx
                                        }
                                    },
                                    onDragEnd = {
                                        dragOffsetY = 0F
                                        draggedItemIndex = -1
                                        isDragged = false
                                    },
                                    onDragCancel = {
                                        dragOffsetY = 0F
                                        draggedItemIndex = -1
                                        isDragged = false
                                    }
                                )
                            }

                    ) {
                        Icon(Icons.Rounded.Menu, "Drag Handle")
                    }
                }
            }

        }
    }
}

It's by no means perfect, but it's a step forward in terms of moving items. I've found an interesting library where they go deeper into the reflection. I hope that could help you. https://github/Calvin-LL/Reorderable

【Here is machine translation】

This is one of the issues where I've gotten the most bang for my buck lately! So while it may not solve your problem, I'd like to give you my implementation code for your reference. Add the dependency first

implementation("sh.calvin.reorderable:reorderable:2.4.3")

After reading your questions and answering the discussion, I believe that the code solution fulfills two of your requirements:

  1. Reorder by dragging and dropping icon

  2. Exchange the specified columns correctly

@Composable
fun VerticalReorderList(routineList:List<Routine>) {
    val view = LocalView.current
    /*
    * Custom data classes are also compatible if required.-use my data class example here
    */
    var list = remember { mutableStateListOf<Routine>().apply {
        addAll(routineList)
    } }
    val lazyListState = rememberLazyListState()
    val reorderableLazyListState = rememberReorderableLazyListState(lazyListState) { from, to ->
        list.apply {
            add(to.index, removeAt(from.index))
        }
        ViewCompat.performHapticFeedback(
            view,
            HapticFeedbackConstantsCompat.SEGMENT_FREQUENT_TICK
        )
    }
    
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        state = lazyListState,
    ) {
        items(
            items = list,
            key = { it.id }
        ) {routine ->
            ReorderableItem(
                state = reorderableLazyListState,
                key =  routine.id
            ) { isDragging ->
                val elevation by animateDpAsState(if (isDragging) 4.dp else 0.dp)
                
                Surface(shadowElevation = elevation) {
                    /*
                    * can be replaced with any UI design
                    */
                    DetailRoutineRow(
                        modifier = Modifier
                            .clickable{ }   //The function here is intended to illustrate the compatibility of multiple gesture detections
                            .swipeToDismiss { },
                    ) {
                        IconButton(
                            modifier = Modifier.draggableHandle(
                                onDragStarted = {
                                    ViewCompat.performHapticFeedback(
                                        view,
                                        HapticFeedbackConstantsCompat.GESTURE_START
                                    )
                                },
                                onDragStopped = {
                                    ViewCompat.performHapticFeedback(
                                        view,
                                        HapticFeedbackConstantsCompat.GESTURE_END
                                    )
                                },
                            ),
                            onClick = {},
                        ) {
                            Icon(Icons.Rounded.DragHandle, contentDescription = "Reorder")
                        }
                    }
                }
            }
        }
    }
}

by the way,anyone Know how to add images? my gif forever "Image upload failed. Please try again."

发布评论

评论列表(0)

  1. 暂无评论