以程序方式结束 Android DragEvent

7

我正在使用3.0中引入的拖放API,但是我只想在用户位于屏幕上特定区域时跟随手指拖动。如果他们漂移到该区域之外,我希望影子消失并结束拖动事件。我已经进行了一些搜索,并看到API不支持创建后更新拖动影子,这是我的第一个计划,但是否有任何方法可以在用户实际抬起手指之前停止DragEvent事件?

2个回答

2
有两个 API 调用适用于 API 24+,它们应该很有用: View#cancelDragAndDrop 取消正在进行的拖放操作。一个 DragEvent 对象将被发送到每个接收了 DragEvent.ACTION_DRAG_STARTED 的 View,即使它们当前不可见,其中 DragEvent.getAction() 的值为 DragEvent.ACTION_DRAG_ENDED,DragEvent.getResult() 的值为 false。
可以在任何与 startDragAndDrop 被调用的 View 相同的窗口上调用此方法。
View#updateDragShadow 更新正在进行的拖放操作的拖影。
你使用哪个方法以及如何使用它们将取决于你的意图。如果你只需要拖动阴影在移出定义区域时消失,而不是结束拖放操作,这样如果用户将其移回感兴趣的区域,拖动阴影将再次出现,那么updateDragShadow就足够了。如果你想要完全取消拖放操作,使用cancelDragAndDrop
问题没有定义“在屏幕上特定区域内”的含义。我假设它是视图的一部分。在拖动监听器中,你可以使用拖动视图坐标来确定拖动视图是否在区域内或外。拖动视图坐标可以在DragEvent中找到。另一个选择是定义一个空视图覆盖屏幕区域,并在拖动视图退出该视图时采取行动。(你还需要在该空视图上设置拖放监听器。)
以上不适用于API 23及以下版本,对于这些较低的API,解决方案并不立即明显。拖动阴影具有内部表示形式,据我所知,无法通过API访问,尽管您可能可以通过反射做一些事情。 View.java 包含有关拖放操作的内部信息。

0

这个问题很老,但由于没有答案; 我想提醒大家,根据官方文档和API here,这现在是默认行为。

可以使用以下引用代码实现此行为:

val imageView = ImageView(this)

// Set the drag event listener for the View.
imageView.setOnDragListener { v, e ->

    // Handles each of the expected events.
    when (e.action) {
        DragEvent.ACTION_DRAG_STARTED -> {
            // Determines if this View can accept the dragged data.
            if (e.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
                // As an example of what your application might do, applies a blue color tint
                // to the View to indicate that it can accept data.
                (v as? ImageView)?.setColorFilter(Color.BLUE)

                // Invalidate the view to force a redraw in the new tint.
                v.invalidate()

                // Returns true to indicate that the View can accept the dragged data.
                true
            } else {
                // Returns false to indicate that, during the current drag and drop operation,
                // this View will not receive events again until ACTION_DRAG_ENDED is sent.
                false
            }
        }
        DragEvent.ACTION_DRAG_ENTERED -> {
            // Applies a green tint to the View.
            (v as? ImageView)?.setColorFilter(Color.GREEN)

            // Invalidates the view to force a redraw in the new tint.
            v.invalidate()

            // Returns true; the value is ignored.
            true
        }

        DragEvent.ACTION_DRAG_LOCATION ->
            // Ignore the event.
            true
        DragEvent.ACTION_DRAG_EXITED -> {
            // Resets the color tint to blue.
            (v as? ImageView)?.setColorFilter(Color.BLUE)

            // Invalidates the view to force a redraw in the new tint.
            v.invalidate()

            // Returns true; the value is ignored.
            true
        }
        DragEvent.ACTION_DROP -> {
            // Gets the item containing the dragged data.
            val item: ClipData.Item = e.clipData.getItemAt(0)

            // Gets the text data from the item.
            val dragData = item.text

            // Displays a message containing the dragged data.
            Toast.makeText(this, "Dragged data is $dragData", Toast.LENGTH_LONG).show()

            // Turns off any color tints.
            (v as? ImageView)?.clearColorFilter()

            // Invalidates the view to force a redraw.
            v.invalidate()

            // Returns true. DragEvent.getResult() will return true.
            true
        }

        DragEvent.ACTION_DRAG_ENDED -> {
            // Turns off any color tinting.
            (v as? ImageView)?.clearColorFilter()

            // Invalidates the view to force a redraw.
            v.invalidate()

            // Does a getResult(), and displays what happened.
            when(e.result) {
                true ->
                    Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG)
                else ->
                    Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG)
            }.show()

            // Returns true; the value is ignored.
            true
        }
        else -> {
            // An unknown action type was received.
            Log.e("DragDrop Example", "Unknown action type received by View.OnDragListener.")
            false
        }
    }
}

我是赏金发起人,我已经从文档中看到了这个例子。然而,除非我漏看了什么,不幸的是它并没有做到问题所要求的。目标是在用户没有抬起手指的情况下编程方式停止拖动过程(并停止显示拖影)。该示例未展示此功能。我基本上正在寻找View.stopDragAndDrop()的等效方法(该方法不存在)。因此,问题是:是否可能模仿这样一个想象中的方法,通过它我们可以强制停止拖动过程并停止显示拖影? - Decent Dabbler
如果我理解正确,您想在用户仍然按住并拖动的情况下取消拖动?如果是这样,您尝试过在拖动视图v时使用 v.clearColorFilter()v.invalidate() 吗? - Jagar
是的,你理解得没错。然而,v.clearColorFilter()v.invalidate()与放置目标有关,而不是所谓的“拖影”。拖影基本上是被拖动的项目的表示,在屏幕上拖动。Panagiotis Giannoutsos似乎提供了一个创建自定义拖影的解决方案,然后通过检查DragEvent坐标对其进行操作。但我需要深入研究这篇文章,才能完全理解它的可能性。 - Decent Dabbler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接