[Solved] iOS Style Rearrange of Icons
Page |
1 |
Lets say I have several rectangles on a page arranged in a grid. I want to implement the iPhone/iPad feature where a user can click and hold on a rectangle, signal to the user that he can move them (iOS does squiggly movement), and then allow him to rearrange the icons while the other icons fill in around his movement. He also needs a button on the interface to stop the rearrange mode. Does this make sense?
How could I implement something like this in QML.
21 replies
What you are proposing is quite complicated to to begin with. I would start writing on paper a state machine of the basic states that are needed. The default state is easy, the “squiggly” state is entered when someone long-presses the MouseArea, and is the same but adds animations to the rectangles, and allows dragging of them, etc.
The next one is probably the harder. I have no idea on how to do it, since I haven’t played with dragging stuff.
Isn’t this exactly what a GridView [doc.qt.nokia.com] does?
You can use an onPressAndHold [doc.qt.nokia.com] inside the delegate to wait for the users action and then reparent that item to move it.
The other items will slide in to position (you can use onRemove [doc.qt.nokia.com] signal).
Not quite sure what you mean by a ‘squiggle’. I assume you just mean some sort of animation related to ‘loading’ though.
I will show how I manage loading events. I use a rotating circle with different shades of black along the perimeter:
loading.png
http://goo.gl/SDG7T
Loading.qml
- import QtQuick 1.0
- Image {
- id: loading; source: "images/loading.png"
- NumberAnimation on rotation {
- from: 0; to: 360; running: loading.visible == true; loops: Animation.Infinite; duration: 900
- }
- }
You could just have the Loading item inside your delegate then:
- Loading { id: squiggle; width:36; height:36; visible: false }
There are a few ways to enable/disable the Loading element. One way is to use the onPressed signal to make the Loading element visible (visible = true) and onReleased to make it invisible (visible = false).
- onPressed: squiggle.visible = true
- onReleased: squiggle.visible = false
You would also make it invisible when the onPressAndHold enters though, as it will be reparented as that stage and not part of the GridView. Makes sense I think :).
Squiggly refers to the slight rotation oscillation on the icons when in a moveable state. Here is a video [youtube.com]
Oh, I see.
Not sure if the OP wants to replicate this effect exactly as it seems a bit silly and obvious copying if you used it.
However, to do this, you would have to make use of States.
- GridView {
- id: view
- ...
- states: [
- State {
- name: "normal";
- ...
- },
- State {
- name: "squiggle";
- ...
- },
- ]
- }
Inside the delegate you would use:
- onPressAndHold: {
- // code mentioned above for reparenting item
- ...
- view.state="squiggle"
- }
Then you would have code within the delegate for the animation, as follows:
- Image {
- id: icon;
- source: modelImageUrl // derived from model
- NumberAnimation on rotation {
- from: -40; to: 40; running: view.state=="squiggle"; loops: Animation.Infinite; duration: 400
- }
- }
I haven’t tested that rotation out but I assume it loops -40, 40, -40. 400ms per side. Which is what you would want.
I can confirm this.
Where your model is:
- model: EventModel {id: listmodel}
You can remove the object from the grid using:
- listmodel.remove(index)
Or simply move it to the end of the grid while you re-parent it and assign it to a new object:
- listmodel.move(index, listmodel.count - 1, 1)
And the grid will automatically refit. Note: Use the onRemove signal to create a fancy animation to go with this. Or use Behaviour modifiers.
You can also use Flow [doc.qt.nokia.com] QML element as an alternative to GridView. It doesn’t support model/delegate but rather Loader’s and Qt.createObject’s. As there is no predefined order, the order is created only from what appears. So you can remove objects from the view and have them realign depending on visibility/opacity and position.
They will certainly appear as different sizes. However, as Bradley says, the center of the rectangle will not change. There will just be more space around them.
You can change the spacing of the GridView by using cellHeight [doc.qt.nokia.com] and cellWidth [doc.qt.nokia.com] properties.
If you need variable spacing, perhaps you would prefer a Flow element.
I will have to apologize but I started poking around and I cannot figure out the reparenting code. Here is how I have things setup:
- import Qt 4.7
- Rectangle {
- width: 640
- height: 480
- color: "#111111"
- Component {
- id: widgetmodel
- Item {
- width: grid.cellWidth; height: grid.cellHeight
- Column {
- anchors.fill: parent
- Image { source: portrait; anchors.horizontalCenter: parent.horizontalCenter }
- }
- }
- }
- GridView {
- id: grid
- x: 0
- y: 0
- width: 640
- height: 480
- anchors.fill: parent
- cellWidth: 80; cellHeight: 80
- model: WidgetModel {}
- delegate: widgetmodel
- highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
- focus: true
- }
- MouseArea {
- id: mouse_area1
- x: 0
- y: 0
- width: grid.width
- height: grid.height
- onPressAndHold: {
- widgetmodel.move(index, listmodel.count - 1, 1)
- }
- }
- }
You must log in to post a reply. Not a member yet? Register here!





