Drag'n'Drop is an undeniably important element of user interaction and graphical environment. Unfortunately, in QML there is no built-in Drag'n'Drop mechanism for View. Therefore, I wrote a small example based on a GridView with 16 images.
This example of Drag'n'Drop doesn’t claim perfection (there are several other implementations that are visually more perfect), but the aim is to show that QML is a very flexible and simple development tool. ')
For a start, a small video, and under the cat 5 simple steps to get a similar result.
Step 1. Create a GridView
Let's start by creating a GridView and a small model. As test data, I took standard images from the Nokia N8. Let's make our grid size 4x4 images.
After running in qmlviewer, we will see something like the following picture.
Step 2. Add Drag'nDrop
Now we need to add the ability to drag and drop images into this grid.
To simplify the task, disable the ability to scroll the GridView. You can do without it (using a long press instead of the usual pressing for D'n'D and manipulating the interactive property (which is responsible for whether the GridView will scroll) in the corresponding MouseArea callbacks), but this complicates the example.
We will also add a MouseArea element the size of the entire GridView, which will catch the mouse click at the start of the dredge, as well as move the element to the desired position in the model when the mouse is released. Plus, in the GridView we will add another additional dndContainer element, which we'll talk about later
The final touch is to add a property to our GridView to store the current floating element (or rather, its index in the model).
In the delegate, add the inDrag state, which will be activated when this element is relocatable. This is where we need dndContainer . To it we will cling (or to be more precise, then change the parent to this container) our moving element. In addition to changing the parent, we also untie the anchors on the element (so that it can move) and expose x and y, respectively, to the coordinates of the mouse (and thanks to the binding, the position of the untied image will change with the mouse cursor). When the state becomes inactive, all these changes will be rolled back.
Running, we will see something like this. Now, we in our grid can safely move elements.
Step 3. Render the item to be moved.
Ok, we learned to do something for which this article was written (it's simple, isn't it?). But the moved element is almost not noticeable, it is necessary to slightly distinguish it from the rest. Add a white frame around the dragged image. Paste this code into our itemImage .
Plus to the frame, it would be nice to somehow mark the place where the drag element was taken from. Add a white circle in the center of this place. This code is placed next to our itemImage.
In the inDrag state , add another change in the height and width of the image and the transition from this state to any other state (that is, the transition from the active drag'n'drop to the normal mode). In this transition we will make a scale animation.
And this is filmed at the intermediate time when the animation is working.
Step 5. The final touch
And, as a conclusion, we add a position indicator to which the item will be moved. Display it as a vertical bar to the left of this element.
The parent of this element will be our GridView, all actions with it will occur in the same place.
To begin with, we will add three new properties to the GridView: the target element index ( possibleDropIndex ) and the current mouse coordinates ( xCoordinateInPossibleDrop and yCoordinateInPossibleDrop ).
Plus, add the indicator element itself. This is a regular 6x1 pixel image with a gradient spread out vertically. The indicator has two states: invisible (default) and shown . In the second state, the indicator element is placed in the gap between the two pictures, to the left of the target. The position of the element is calculated based on the last two properties, and not by the index in the model, thus we are not dependent on the current number of columns in the table.
Also add another handler to MouseArea. Here we need a property with a drop location index, so as not to update the mouse coordinates each time, but to change them only when the target element changes.