'Programmatically end an Android DragEvent
I am using the Drag & Drop API's introduced in 3.0 - however, I only want the drag shadow to follow the user's finger around while they are inside one particular area of the screen. If they drift outside that, I would like the shadow to go away and the drag event to end. I have already done some searching and seen that the API does not support updating the drag shadow after creation, which was my first plan, but is there any way to stop the DragEvent without the user actually lifting their finger?
Solution 1:[1]
There are two API calls for API 24+ that should be useful:
Cancels an ongoing drag and drop operation.
A DragEvent object with DragEvent.getAction() value of DragEvent.ACTION_DRAG_ENDED and DragEvent.getResult() value of false will be sent to every View that received DragEvent.ACTION_DRAG_STARTED even if they are not currently visible.
This method can be called on any View in the same window as the View on which startDragAndDrop was called.
Updates the drag shadow for the ongoing drag and drop operation.
Which you use and how you use them will depend upon your intentions. If you simply need the drag shadow to disappear when it is moved outside a defined area without ending the drag and drop operation so that the drag shadow will appear again if the user moves it back into the area of interest, updateDragShadow should suffice. If you want to cancel the drag and drop operation completely, use cancelDragAndDrop.
The question doesn't define what "inside one particular area of the screen" means. I assume that it is part of a view. In the drag listener, you can use the drag view coordinates to determine if the drag view is inside or outside the area. The drag view coordinates can be found in DragEvent. Another option would be to define an empty view that covers the area of the screen and take action when the drag view exits that view. (You will need to set a drag and drop listener on that empty view as well.)
The above does not apply to API 23 and below and the solution is not immediately obvious for these lower APIs. The drag shadow has an internal representation that is not accessible through the API as far as I can tell, although you might be able to do something with Reflection. View.java has internal information about the drag and drop operation.
Solution 2:[2]
The question is old but since there is no answer; I want to bring attention that this is now the default behaviour according to the official documentation and API here
This behavior can be achieved using the following quoted code:
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
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Cheticamp |
| Solution 2 | Jagar |
