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 FrameLayoutDragShadow 返回到其原始位置和控制台说 I/ViewRootImpl[MainActivity]: Reporting drop result: false。最后,调用 DragEvent.ACTION_DRAG_ENDED 并使红色 FrameLayout 可见。

所以,这里有问题,

  1. 为什么拖拽失败?这是因为我在同一个 FrameLayout 上释放了拖动,请问它是红色的吗?

  2. 有什么方法可以阻止 DragShadow 回到原来的位置吗?我想要的只是当我释放拖动时,我只希望 FrameLayout 出现在新位置,而不是回到其初始位置。

提前谢谢大家。

对于那些有同样问题的人,我通过使用带有拖放功能的 ItemTouchHelper 的 recyclerview 解决了这个问题。您不必编写自己的代码。