Friday 27 November 2020

Android drag and drop on the same view results in reporting drop result: false

I am trying to make a reorderable GridLayout with drag and drop.

Basically, when I drag something in the GridLayout, it should reorder the GridLayout based on the dragging.

I have this GridLayout which has 6 FrameLayout inside.

<GridLayout
    android:id="@+id/myGridLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:columnCount="3">

    <FrameLayout
        android:background="@android:color/holo_blue_dark"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_columnWeight="1">
    </FrameLayout>

    <FrameLayout
        android:background="@android:color/black"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_columnWeight="1">
    </FrameLayout>

    <FrameLayout
        android:background="@android:color/darker_gray"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_columnWeight="1">
    </FrameLayout>

    <FrameLayout
        android:background="@android:color/holo_green_dark"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_columnWeight="1">
    </FrameLayout>

    <FrameLayout
        android:background="@android:color/holo_purple"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_columnWeight="1">
    </FrameLayout>

    <FrameLayout
        android:background="@android:color/holo_red_dark"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_columnWeight="1">
    </FrameLayout>

</GridLayout>

So It looks like the screenshot below

enter image description here

I have registered all the FrameLayouts in the GridLayout for LongClickListner and DragListener as per the codes below

    for (i in 0 until myGridLayout.childCount) {
        val childView = myGridLayout.getChildAt(i)

        childView.setOnLongClickListener {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                it.visibility = View.INVISIBLE
                it.startDragAndDrop(null, CustomDragShadowBuilder(it, lastTouch), it, 0)
            } else it.startDrag(null, CustomDragShadowBuilder(it, lastTouch), it, 0)
            true
        }


        childView.setOnDragListener { v, event ->
            when (event.action) {
                DragEvent.ACTION_DRAG_STARTED -> true
                DragEvent.ACTION_DRAG_ENTERED -> {
                        val draggingView = event.localState as View
                        val dragEnteredIndex = myGridLayout.indexOfChild(v)
                        val draggingViewIndex = myGridLayout.indexOfChild(draggingView)
                        myGridLayout.removeViewAt(draggingViewIndex)
                        myGridLayout.addView(draggingView, dragEnteredIndex)
                        true
                }
                DragEvent.ACTION_DRAG_LOCATION -> true
                DragEvent.ACTION_DRAG_EXITED -> true
                DragEvent.ACTION_DROP -> true
                DragEvent.ACTION_DRAG_ENDED -> {
                    val draggingView = event.localState as View
                    draggingView.post { run { draggingView.visibility = View.VISIBLE } }
                    true
                }
                else -> false
            }
        }
    }

So, when you drag the red FrameLayout over to gray FrameLayout, the DragEvent.ACTION_DRAG_ENTERED is called. Then, I just remove the red FrameLayout and add it to the index of the gray FrameLayout where the DragShadow is over, so that I can reorder the GridLayout in real time. So, when I move around a FrameLayout in the GridLayout, I have got something like this, which is what I expect.

enter image description here

But, as you can see, when I release the drag, the red FrameLayout, or DragShadow goes back to its original position and console says I/ViewRootImpl[MainActivity]: Reporting drop result: false. Finally, the DragEvent.ACTION_DRAG_ENDED is called and make the red FrameLayout visible.

So, here are questions,

  1. why the drag fails? Is this because I release the drag over the same FrameLayout, which is red one please?

  2. Is there any way that I can prevent the DragShadow from getting back to its original position? What I want is just that when I release my drag, I just want the FrameLayout to appear at the new position, not getting back to its initial position.

Thank you guys in advance.



from Android drag and drop on the same view results in reporting drop result: false

No comments:

Post a Comment