Understanding the Drag and the Drop
In enabling a user to perform a drop and drag action you have a view that is being dragged and a view that is being dragged to. The listener that will activate the drag, e.g. a long press, is attached to the view that will be dragged. While the view that is being dragged to has the drag listener attached to it. A single view can be dragged onto many different views if those views each have drag listeners set and ready to respond positively. Likewise multiple views can be dragged onto the same view that is being dragged to.View Being Dragged To
Starting with the view being dragged to, which is an essential if you are going to be able to drop your draggable view anywhere, we have the following code. (See below for further explanation.)
// A view is identified from the layout file within which other views can be dragged (mainView) RelativeLayout mainView = findViewById(R.id.mainView); mainView.setOnDragListener(new View.OnDragListener() { @Override public boolean onDrag(View view, DragEvent dragEvent) { switch (dragEvent.getAction()) { case ACTION_DRAG_STARTED: return true; case ACTION_DRAG_ENTERED: return true; case ACTION_DRAG_LOCATION: return true; case ACTION_DRAG_EXITED: return true; case ACTION_DROP: float newX = dragEvent.getX(); float newY = dragEvent.getY(); View dragView = (View) dragEvent.getLocalState(); dragView.setX(newX - dragView.getWidth()/2); dragView.setY(newY - dragView.getHeight()/2); return true; case ACTION_DRAG_ENDED: return true; default: return false; } } });
View Being Dragged
Next we have the view being dragged, which starts the process of dragging with the startDrag method. A convenient way to identify the desire to begin dragging is within a long click listener.
// A view is created that will be dragged. ImageView newImg = new ImageView(this); newImg.setMinimumWidth(100); newImg.setMinimumHeight(100); newImg.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); mainView.addView(newImg); imageView.setOnLongClickListener(new View.OnLongClickListener() { // Defines the one method for the interface, which is called when the View is long-clicked public boolean onLongClick(View v) { // Instantiates the drag shadow builder. View.DragShadowBuilder myShadow = new View.DragShadowBuilder(v); // Starts the drag v.startDrag(null, // the data to be dragged myShadow, // the drag shadow builder v, // no need to use local data 0 // flags (not currently used, set to 0) ); return true; } });This is all there is to drag and drop, where the aim is to move a view of some kind to another position. To experiment this code can safely be placed within the opening onCreate method of the MainActivity.
Further Detail
The OnDragListener has a single method contained within its closure: onDrag (View v, DragEvent event).The onDrag method receives a DragEvent instance, which identifies one of six actions
• ACTION_DRAG_STARTED
• ACTION_DRAG_ENTERED
• ACTION_DRAG_LOCATION
• ACTION_DROP
• ACTION_DRAG_EXITED
• ACTION_DRAG_ENDED
through a getAction() call. It is then your responsibility to response true or false as to whether the action has been handled. Returning true identifies that the action has been handled successfully, returning false indicates failure.
The view passed to the onDrag method is the view being dragged to, while the event holds all the DragEvent information.
We don’t have a direct reference to the view being dragged and you might think that you need to somehow code this information into the ClipData (which can be transported with the drag - see Android Developer Docs on Drag and Drop) but thankfully this isn’t the case because this information can be retrieved by casting the local state to a View.
This casting of the local state is a somewhat mysterious act because all we know about the local state from the docs is that:
The object is intended to provide local information about the drag and drop operation. For example, it can indicate whether the drag and drop operation is a copy or a move.And so you would expect to work through an array of objects, or such like to arrive at the reference to the view being dragged. But no, a simple cast is all that is required, and presumably copy and move data is extracted in a similar way, but I have not yet investigated this.
The local state is available only to views in the activity which has started the drag operation. In all other activities this method will return null
This method returns valid data for all event actions.
Comments
Post a Comment