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
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.
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,
why the drag fails? Is this because I release the drag over the same FrameLayout
, which is red one please?
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.
For those who have the same issues, I solved this isseus by using recyclerview with ItemTouchHelper which does have drag and drop featuers. You don't have to do your own codes.