Android 在同一视图上拖放导致报告放置结果:false
Android drag and drop on the same view results in reporting drop result: false
我正在尝试通过拖放制作可重新订购的 GridLayout
。
基本上,当我在 GridLayout
中拖动某些东西时,它应该根据拖动对 GridLayout
重新排序。
我有这个 GridLayout
,里面有 6 个 FrameLayout
。
<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>
所以看起来像下面的截图
我已经按照以下代码在 GridLayout
中为 LongClickListner 和 DragListener 注册了所有 FrameLayouts
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
}
}
}
因此,当您将 红色 FrameLayout
拖到 灰色 FrameLayout
时,DragEvent.ACTION_DRAG_ENTERED
被调用。然后,我只是删除 red FrameLayout
并将其添加到 gray FrameLayout
的索引中 DragShadow
结束了,这样我就可以实时重新排序 GridLayout
了。所以,当我在 GridLayout
中移动 FrameLayout
时,我得到了这样的东西,这正是我所期望的。
但是,如您所见,当我释放拖动时,red FrameLayout
或 DragShadow
返回到其原始位置和控制台说 I/ViewRootImpl[MainActivity]: Reporting drop result: false
。最后,调用 DragEvent.ACTION_DRAG_ENDED
并使红色 FrameLayout
可见。
所以,这里有问题,
为什么拖拽失败?这是因为我在同一个 FrameLayout
上释放了拖动,请问它是红色的吗?
有什么方法可以阻止 DragShadow
回到原来的位置吗?我想要的只是当我释放拖动时,我只希望 FrameLayout
出现在新位置,而不是回到其初始位置。
提前谢谢大家。
对于那些有同样问题的人,我通过使用带有拖放功能的 ItemTouchHelper 的 recyclerview 解决了这个问题。您不必编写自己的代码。
我正在尝试通过拖放制作可重新订购的 GridLayout
。
基本上,当我在 GridLayout
中拖动某些东西时,它应该根据拖动对 GridLayout
重新排序。
我有这个 GridLayout
,里面有 6 个 FrameLayout
。
<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>
所以看起来像下面的截图
我已经按照以下代码在 GridLayout
中为 LongClickListner 和 DragListener 注册了所有 FrameLayouts
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
}
}
}
因此,当您将 红色 FrameLayout
拖到 灰色 FrameLayout
时,DragEvent.ACTION_DRAG_ENTERED
被调用。然后,我只是删除 red FrameLayout
并将其添加到 gray FrameLayout
的索引中 DragShadow
结束了,这样我就可以实时重新排序 GridLayout
了。所以,当我在 GridLayout
中移动 FrameLayout
时,我得到了这样的东西,这正是我所期望的。
但是,如您所见,当我释放拖动时,red FrameLayout
或 DragShadow
返回到其原始位置和控制台说 I/ViewRootImpl[MainActivity]: Reporting drop result: false
。最后,调用 DragEvent.ACTION_DRAG_ENDED
并使红色 FrameLayout
可见。
所以,这里有问题,
为什么拖拽失败?这是因为我在同一个
FrameLayout
上释放了拖动,请问它是红色的吗?有什么方法可以阻止
DragShadow
回到原来的位置吗?我想要的只是当我释放拖动时,我只希望FrameLayout
出现在新位置,而不是回到其初始位置。
提前谢谢大家。
对于那些有同样问题的人,我通过使用带有拖放功能的 ItemTouchHelper 的 recyclerview 解决了这个问题。您不必编写自己的代码。